2011-07-20 51 views
10

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

见这个例子:

enum Field 
{ 
    Name, 
    Date, 
} 

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

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

回答

15

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

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

要可靠地获取索引器属性的实际名称,您必须反思该类并获得DefaultMember attribute
更多信息可查询here

+0

*“通常” *的时候是不是?你怎么能可靠地得到它? –

+4

可以使用索引器上的“IndexerName”属性进行更改。您可以反思包含索引器的类并检索'DefaultMember'属性以可靠地获取索引器属性的名称。请参阅[这里](http://social.msdn.microsoft.com/Forums/en-US/vstscode/thread/60de101a-278d-4674-bc1a-0a04210d566c)了解更多信息。 –

+0

非常感谢。它真的有用 - Expression.Property(参数,“Item”,Expression.Constant(...)) – Ondra

12

我会发布关于如何使用一个索引一个完整的例子:

ParameterExpression dictExpr = Expression.Parameter(typeof(Dictionary<string, int>)); 
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<PropertyInfo>() 
         // 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<Action<Dictionary<string, int>, string, int>>(assign, dictExpr, keyExpr, valueExpr); 
var lambdaGetter = Expression.Lambda<Func<Dictionary<string, int>, string, int>>(indexExpr, dictExpr, keyExpr); 
var setter = lambdaSetter.Compile(); 
var getter = lambdaGetter.Compile(); 

var dict = new Dictionary<string, int>(); 
setter(dict, "MyKey", 2); 
var value = getter(dict, "MyKey"); 

要从IndexExpression直接包含索引属性的值索引读取。要写信给我们,我们必须使用Expression.Assign。其他一切都相当香草Expression。正如丹尼尔所写,索引者通常被称为“项目”。请注意,Expression.Property有一个直接接受索引器名称的过载(所以"Item"),但我选择手动查找它(以便可以重用)。我甚至举了一个例子来说明如何使用LINQ来找到你想要的索引器的确切超载。

就像一个好奇,如果你看看MSDN例如用于DictionaryProperties下,你会发现Item