从表达式树访问索引器

Ond*_*dra 15 c# expression-trees

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

看这个例子:

enum Field
{
    Name,
    Date,
}

class ObjectModel
{
    object this[Field Key]
    {
        get 
        {
            //...
            return xx;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

xan*_*tos 18

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

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");
Run Code Online (Sandbox Code Playgroud)

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

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


Dan*_*rth 17

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

索引属性的名称可以通过类的实现者通过来改变IndexerName属性.

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

  • 它可以使用索引器上的`IndexerName`属性进行更改.您可以反映包含索引器的类,并检索`DefaultMember`属性以可靠地获取索引器属性的名称.有关详细信息,请参阅[此处](http://social.msdn.microsoft.com/Forums/en-US/vstscode/thread/60de101a-278d-4674-bc1a-0a04210d566c). (4认同)