Lambda属性名称和数组索引

4
对于以下Lambda表达式:
GetPropertyNameAndArrayIndex(() => SomeArray[0])

我知道你可以获取表达式的 属性名称。我也知道你可以使用 ConstantExpression 并访问 Right 值来获取数组索引。我的问题是,当它不是常量时,如何获取数组索引(或右值),例如:

for (int i = 0; i < 5; i++)
{
    GetPropertyNameAndArrayIndex(() => SomeArray[i])
}

任何帮助都将不胜感激。

请编辑。在“我知道你可以[缺少的动词]属性名称和数组索引”中缺少一个动词。 - Emilio M Bumachar
@Emilio,感谢您指出我的语法不好 :) - Kane
3
小心那段代码片段:lambda表达式将会捕获闭包中的变量i,而不是它创建时的值。如果稍后调用函数,所有迭代中创建的表达式都将被视为在最后一次迭代中创建。 - Joel Coehoorn
澄清一下:我认为你在这里可能没问题,因为每次迭代似乎都会调用和使用lambda委托,然后再继续下一个,而不是将其保存在某个地方。但还是值得记住的。 - Joel Coehoorn
1个回答

3

如评论中已经指出的那样;请注意,如果在异步模式下使用,所给出的示例容易受到捕获变量问题的影响,但可能“原样”使用。

要彻底完成这项工作涉及很多边缘情况(或者您可以作弊并使用Compile())- 但这里是一个展示整体主题的示例(不使用Compile()):

using System;
using System.Linq.Expressions;
using System.Reflection;
class Program
{
    static void Main()
    {
        string[] arr = { "abc", "def" };
        for (int i = 0; i < arr.Length; i++)
        {
            Foo(() => arr[i]);
        }
    }
    static object Foo<T>(Expression<Func<T>> lambda)
    {
        object obj = Walk(lambda.Body);
        Console.WriteLine("Value is: " + obj);
        return obj;

    }
    static object Walk(Expression expr)
    {
        switch (expr.NodeType)
        {
            case ExpressionType.ArrayIndex:

                BinaryExpression be = (BinaryExpression)expr;
                Array arr = (Array)Walk(be.Left);
                int index = (int) Walk(be.Right);
                Console.WriteLine("Index is: " + index);
                return arr.GetValue(index);
            case ExpressionType.MemberAccess:
                MemberExpression me = (MemberExpression)expr;
                switch (me.Member.MemberType)
                {
                    case MemberTypes.Property:
                        return ((PropertyInfo)me.Member).GetValue(Walk(me.Expression), null);
                    case MemberTypes.Field:
                        return ((FieldInfo)me.Member).GetValue(Walk(me.Expression));
                    default:
                        throw new NotSupportedException();
                }
            case ExpressionType.Constant:
                return ((ConstantExpression) expr).Value;
            default:
                throw new NotSupportedException();

        }
    }

}

这是一个完整的可行走列表吗? - Maslow
@Maslow 绝对不是这样。我在某个地方有一个更完整的3.5列表,但这在4.0中再次增长。诀窍是要弄清楚您需要支持哪些场景范围。 - Marc Gravell
@Maslow - 我们不是在电子邮件中讨论过这个问题吗?听起来很熟悉。 - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接