Справка по динамической библиотеке Linq - PullRequest
0 голосов
/ 28 марта 2010

У меня есть следующий класс:

public class Item
{
    public Dictionary<string, string> Data
    {
        get;
        set;
    }
}

и список его:

List<Item> items;

Мне нужно отфильтровать и упорядочить этот список динамически, используя строки в стиле SQL. Подвох в том, что мне нужно упорядочить его по словарю данных.

Например: Order By Data["lastname"] или Where Data["Name"].StartsWith("a"). Я подумал использовать динамическую библиотеку linq, но есть ли способ, которым мои клиенты могут писать без данных []? Например:

Name.StartsWith("abc")

вместо

Data["Name"].StartsWith("abc")

Ответы [ 3 ]

1 голос
/ 28 марта 2010

Это не имеет ничего общего с модулем динамического запроса Linq. Эта единица предназначена для случаев, когда у вас есть фактические поля / свойства, и их имена будут предоставлены вам во время выполнения. Другими словами, у вас есть такой класс:

public class Person
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

И вы хотите написать запрос:

var sortedPeople = people.OrderBy("FirstName");

Вы пытаетесь сделать полную противоположность этому - у вас есть класс, который не имеет никаких реальных свойств, просто словарь атрибутов, и вы хотите безопасность во время компиляции. Вы не можете иметь это; нет никакого способа гарантировать, что элемент будет в словаре, , особенно , когда словарь общедоступен, и любой может добавить / удалить его прямо из него!

Если есть какая-то причина, по которой вы должны использовать этот конкретный дизайн класса, тогда вы могли бы написать некоторые обертки, как представил Ник, но я бы даже не стал беспокоиться - на самом деле они не обеспечивают инкапсуляцию потому что словарь Data по-прежнему широко открыт для всего мира. Вместо этого я бы просто предоставил один безопасный метод получения или свойство индексатора и создал бы несколько констант (или перечисление) с именами свойств, в которых вы ожидаете находиться.

public class Item
{
    public Dictionary<string, string> Data { get; set; }

    public string GetValue(string key)
    {
        if (Data == null)
            return null;
        string result;
        Data.TryGetValue(key, out result);
        return result;
    }
}

public class ItemKeys
{
    public const string Name = "Name";
    public const string Foo = "Foo";
}

и так далее. На самом деле ItemKeys не так важен, важен безопасный GetValue метод, потому что в противном случае вы рискуете получить NullReferenceException, если Data не было назначено, или KeyNotFoundException, если даже один Item экземпляр не имеет этого свойства. Использование метода GetValue здесь будет успешным, несмотря ни на что:

var myItems = items.OrderBy(i => i.GetValue(ItemKeys.Name));

Если вы обнаружите, что пишете много повторяющегося кода для одних и тех же атрибутов, , тогда начните беспокоиться о добавлении в класс свойств быстрого доступа или методов расширения.

1 голос
/ 28 марта 2010

Вы можете добавить свойство как это:

public class Item
{
    public Dictionary<string, string> Data
    { get; set; }

    public string Name { get { return Data["lastname"]; } }
}
//Call by: i.Name.StartsWith("abc");

Или метод расширения:

public static class ItemExtensions 
{
  public static string Name(this Item item)
  {
    return item.Data["lastname"];
  }
}
//Call by: i.Name().StartsWith("abc");

Или, если это очень широко используемый метод, вы можете добавить что-то вроде .NameStartsWith():

public static string NameStartsWith(this Item item, stirng start)
{
  return item.Data["lastname"].StartsWith(start);
}
//Call by: i.NameStartsWith("abc");
0 голосов
/ 28 марта 2010

Я предполагаю, что вы не знаете имен свойств во время компиляции (в этом случае вы могли бы просто определить свойства и не иметь этой проблемы). У меня есть два предложения, которые вы можете попробовать, но я сам не реализовал ни одного из них, поэтому не могу гарантировать, что это сработает.

  • Если вы можете использовать .NET 4.0, вы можете наследовать от DynamicObject и реализовать метод TryGetMember (который вызывается, когда вы используете o.Foo для объекта, объявленного как dynamic). Предполагая, что Dynamic LINQ работает с DLR, он должен автоматически вызывать этот метод для объектов, которые наследуются от DynamicObject. Внутри метода TryGetMember вы получите имя доступного свойства, чтобы вы могли выполнить поиск по словарю. (Однако это решение будет работать, только если Dynamic LINQ хорошо интегрируется с DLR).

  • В любом случае, вы можете выполнить базовый анализ введенной пользователем строки и заменить, например, Name на Data["Name"]. Это определенно будет работать, но это может быть немного сложно (потому что вы, вероятно, должны хотя бы проверить, что вы делаете замену в правильном контексте - например, не внутри строковой константы).

Относительно методов расширения - я не уверен, что Dynamic LINQ обрабатывает методы расширения (но я так не думаю, потому что для этого потребуется поиск по всем ссылочным сборкам)

...