从表达式树访问索引器

发布于 2024-11-25 11:08:27 字数 329 浏览 1 评论 0原文

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

请参阅此示例:

enum Field
{
    Name,
    Date,
}

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

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

I am working on a filtering function. The filter will be an expression tree build by an user. There will be about 30 fields the user can use for filtering. I think the best way is to create the object model with indexer and to access required values by index of enum type.

See this example:

enum Field
{
    Name,
    Date,
}

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

I would like to ask how can I access an indexer from an expression tree.

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

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

发布评论

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

评论(2

蒲公英的约定 2024-12-02 11:08:27

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

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。正如 Daniel 所写,索引器通常称为“Item”。请注意,Expression.Property 有一个重载,它直接接受索引器的名称(因此 "Item"),但我选择手动查找它(因此可以重用它) )。我什至举了一个示例,介绍如何使用 LINQ 来查找您想要的索引器的确切重载。

出于好奇,如果您在 MSDN 上查看 字典,在属性,您会发现项目

I'll post a complete example on how to use an indexer:

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

To read from the indexer the IndexExpression contains directly the value of the indexed property. To write to it we must use Expression.Assign. Everything else is quite vanilla Expression. As written by Daniel the Indexer is normally called "Item". Note that Expression.Property has an overload that accepts directly the name of the indexer (so "Item"), but I chose to find it manually (so it can be reused). I have even put an example on how to use LINQ to find the exact overload of indexer you want.

Just as a curiosity, if you look on MSDN for example for Dictionary, under Properties you'll find Item

万劫不复 2024-12-02 11:08:27

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

类的实现者可以通过 IndexerName 属性

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

The indexer is a simple property, normally called Item. This means, you can access the indexer like any other property by using its name.

The name of the indexer property can be changed by the implementor of the class by means of the IndexerName attribute.

To reliably get the actual name of the indexer property, you have to reflect on the class and obtain the DefaultMember attribute.
More information can be found here.

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