动态 Linq 库帮助

发布于 2024-08-27 08:57:32 字数 540 浏览 7 评论 0原文

我有以下类:

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

及其列表:

List<Item> items;

我需要使用类似 SQL 的字符串动态过滤和排序该列表。问题是,我需要通过数据字典对其进行排序。

例如:按数据["lastname"]排序或Where Data["Name"].StartsWith("a")。我想使用动态 linq 库,但是有什么方法可以让我的客户在没有 Data[] 的情况下进行编写吗?例如:

Name.StartsWith("abc")

而不是

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

I have the following class:

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

and a list of it:

List<Item> items;

I need to filter and order this list dynamically using SQL-Like strings. The catch is, that I need to order it by the Data dictionary.

For example: Order By Data["lastname"] or Where Data["Name"].StartsWith("a"). I thought to use the dynamic linq library, but is there any way that my clients can write without the Data[]? For example:

Name.StartsWith("abc")

instead of

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

?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

铜锣湾横着走 2024-09-03 08:57:32

您可以添加如下属性:

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");

You could add a property like this:

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

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

Or an extension method:

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

Or if it's a very commonly used method, you could add something like a .NameStartsWith():

public static string NameStartsWith(this Item item, stirng start)
{
  return item.Data["lastname"].StartsWith(start);
}
//Call by: i.NameStartsWith("abc");
友谊不毕业 2024-09-03 08:57:32

这与 Linq 动态查询单元没有任何关系。该单元适用于您拥有实际字段/属性并且它们的名称将在运行时提供给您的情况。换句话说,你有一个像这样的类:

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

并且你希望能够编写这样的查询:

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

你正在尝试做与此完全相反的事情 - 你有一个类没有任何实际属性,只是一个属性字典,并且您希望编译时安全。你不能拥有它;无法保证某个项目会出现在字典中,尤其当字典是公共的并且任何人都可以直接添加/删除时!

如果出于某种原因您必须使用特定的类设计,那么您可以想象像 Nick 所介绍的那样编写一些包装器,但我什至不会打扰 - 它们实际上并没有提供任何封装,因为Data 字典仍然向全世界开放。相反,我只提供一个安全 getter 方法或索引器属性,并使用您期望在其中的属性名称创建一些常量(或枚举)。

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 尚未分配,或者如果甚至有一个 Item 实例不具有该属性,则会出现 KeyNotFoundException。无论如何,在这里使用 GetValue 方法都会成功:

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

如果您发现自己正在为相同的属性编写大量重复代码,那么就开始担心添加快捷方式属性或类的扩展方法。

This doesn't have anything to do with the Linq Dynamic Query unit. That unit is for when you have actual fields/properties and the names of them will be given to you at runtime. In other words, you have a class like this:

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

And you want to be able to write a query like this:

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

You are trying to do the exact opposite of this - you have a class that does not have any actual properties, just an attribute dictionary, and you want compile-time safety. You can't have it; there's no way to guarantee that an item will be in the dictionary, especially when the dictionary is public and anyone can add/remove directly from it!

If there's some reason that you must use that specific class design, then you could conceivably write some wrappers as Nick has presented, but I wouldn't even bother - they're not actually providing any encapsulation because the Data dictionary is still wide open to the whole world. Instead, I would just provide a single safe getter method or indexer property and create a few constants (or an enum) with the names of properties you expect to be in there.

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";
}

And so on. Really the ItemKeys isn't that important, the safe GetValue method is what's important, because otherwise you run the risk of a NullReferenceException if Data hasn't been assigned, or a KeyNotFoundException if even one Item instance doesn't have that property. Using the GetValue method here will succeed no matter what:

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

If you find you're writing a lot of repetitive code for the same attributes, then start worrying about adding shortcut properties or extension methods to the class.

得不到的就毁灭 2024-09-03 08:57:32

我假设您在编译时不知道属性的名称(在这种情况下,您可以简单地定义属性并且不会出现此问题)。我有两个建议你可以尝试,但我自己没有实施任何一个,所以我不能保证它会起作用。

  • 如果您可以使用.NET 4.0,您可以继承DynamicObject并实现TryGetMember方法(当您使用o.Foo时调用该方法) > 在声明为动态的对象上)。假设 Dynamic LINQ 与 DLR 一起使用,它应该自动为从 DynamicObject 继承的对象调用此方法。在 TryGetMember 方法中,您将获得所访问属性的名称,以便您可以执行字典查找。 (但是,只有 Dynamic LINQ 与 DLR 良好集成时,此解决方案才有效)。

  • 无论如何,您都可以对用户输入的字符串进行一些基本解析,并将例如 Name 替换为 Data["Name"]。这肯定会起作用,但可能有点困难(因为您可能至少应该检查是否在正确的上下文中进行替换 - 例如不在字符串常量内)。

关于扩展方法 - 我不确定 Dynamic LINQ 是否处理扩展方法(但是,我不这么认为,因为这需要搜索所有引用的程序集)

I assume that you don't know the names of the properties at compile-time (in which case, you could simply define properties and wouldn't have this problem). I have two suggestions that you could try, but I didn't implement any of them myself, so I can't guarantee that it will work.

  • If you can use .NET 4.0, you could inherit from DynamicObject and implement TryGetMember method (which is called when you use o.Foo on an object that is declared as dynamic). Assuming that Dynamic LINQ works with DLR, it should automatically invoke this method for objects that inherit from DynamicObject. Inside the TryGetMember method, you would get a name of the accessed property, so you could perform a dictionary lookup. (However, this solution would work only if Dynamic LINQ integrates well with DLR).

  • In any case, you could do some basic parsing of the string entered by the user and replace for example Name with Data["Name"]. This would definitely work, but it may be a bit difficult (because you should probably at least check that you're doing the replace in correct context - e.g. not inside a string constant).

Regarding extension methods - I'm not sure if Dynamic LINQ handles extension methods (but, I don't think so, because that would require searching all referenced assemblies)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文