从表达式树访问索引器

我正在研究过滤function。 filter将是用户构建的表达式树。 用户可以使用大约30个字段进行过滤。 我认为最好的方法是使用索引器创建对象模型,并通过枚举类型的索引访问所需的值。

看这个例子:

enum Field { Name, Date, } class ObjectModel { object this[Field Key] { get { //... return xx; } } } 

我想问一下如何从表达式树中访问索引器。

索引器是一个简单的属性,通常称为Item 。 这意味着,您可以使用其名称访问索引器,就像任何其他属性一样。

可以通过IndexerName属性由类的实现者更改索引器属性的名称。

要可靠地获取索引器属性的实际名称,您必须反映该类并获取DefaultMember属性 。
更多信息可以在这里找到。

我将发布一个关于如何使用索引器的完整示例:

 ParameterExpression dictExpr = Expression.Parameter(typeof(Dictionary)); ParameterExpression keyExpr = Expression.Parameter(typeof(string)); ParameterExpression valueExpr = Expression.Parameter(typeof(int)); // Simple and direct. Should normally be enough // PropertyInfo indexer = dictExpr.Type.GetProperty("Item"); // Alternative, note that we could even look for the type of parameters, if there are indexer overloads. PropertyInfo indexer = (from p in dictExpr.Type.GetDefaultMembers().OfType() // This check is probably useless. You can't overload on return value in C#. where p.PropertyType == typeof(int) let q = p.GetIndexParameters() // Here we can search for the exact overload. Length is the number of "parameters" of the indexer, and then we can check for their type. where q.Length == 1 && q[0].ParameterType == typeof(string) select p).Single(); IndexExpression indexExpr = Expression.Property(dictExpr, indexer, keyExpr); BinaryExpression assign = Expression.Assign(indexExpr, valueExpr); var lambdaSetter = Expression.Lambda, string, int>>(assign, dictExpr, keyExpr, valueExpr); var lambdaGetter = Expression.Lambda, string, int>>(indexExpr, dictExpr, keyExpr); var setter = lambdaSetter.Compile(); var getter = lambdaGetter.Compile(); var dict = new Dictionary(); setter(dict, "MyKey", 2); var value = getter(dict, "MyKey"); 

要从索引器读取, IndexExpression直接包含索引属性的值。 要写入它,我们必须使用Expression.Assign 。 其他一切都是非常香草的Expression 。 正如Daniel所写,Indexer通常被称为“Item”。 请注意, Expression.Property有一个直接接受索引器名称的重载(所以"Item" ),但我选择手动找到它(因此可以重复使用)。 我甚至举例说明如何使用LINQ来找到你想要的索引器的确切重载。

正如好奇心一样,如果您在MSDN上查看“ 词典” ,请在“ 属性”下找到“ 项目”