c# - 获取对作为函数传递的 Lambda 中的参数的引用

标签 c# lambda func

给定以下一组类:

public class MyClass
{
    public int MyInt { get; set; }
}    

public class ObjectProcessor
{
    public int ProcessObject(MyClass myClass)
    {
        return myClass.MyInt ++;
    } 
}

public class Runner
{
    public void Run()
    {
        var classToPass = new MyClass();

        FuncExecutor.ExecuteAction<MyClass>(x => x.ProcessObject(classToPass));
    }
}

public static class FuncExecutor
{
    public static void ExecuteAction<T>(Expression<Func<ObjectProcessor, int>> expression)
    {
        // var func = expression.Compile(); ... does having an Expression help?

        // How can I get a reference to 'classToPass' at this point?

        // The 'classToPass' Type is known to be 'T', in this case 'MyClass'.
    }
}

ExecuteAction 方法中,如何获取对传递给 ProcessObjectclassToPass 实例的引用?

编辑:评论强调了尝试解析表达式树的复杂性,表达式树的组成可能差异很大。

但是,在这种特殊情况下,有两个事实可以大大减少这种变化:

  • ProcessObject 只会接受一个参数。
  • 参数类型是预先知道的。

更改代码以表达这一点。

最佳答案

非常具体地回答:

public class Runner
{
    public void Run()
    {
        var classToPass = new MyClass();
        classToPass.MyInt = 42;

        FuncExecutor.ExecuteAction(x => x.ProcessObject(classToPass));
    }
}

public class FuncExecutor
{
    public static void ExecuteAction(Expression<Func<ObjectProcessor, int>> expression)
    {
        var lambdaExpression = (LambdaExpression)expression;
        var methodCallExpression = (MethodCallExpression)lambdaExpression.Body;

        var memberExpression = (MemberExpression)methodCallExpression.Arguments[0];
        var constantExpression = (ConstantExpression)memberExpression.Expression;
        var fieldInfo = (FieldInfo)memberExpression.Member;

        var myClassReference = (MyClass) fieldInfo.GetValue(constantExpression.Value);

        Console.WriteLine(myClassReference.MyInt); // prints "42"
    }
}

请注意,当您将 lambda 传递给 ExecuteAction 方法时,您会捕获一个局部变量引用 (classToPass)。编译器将生成一些代码来正确处理它。更准确地说,它将生成一个具有类型 MyClass 的单个成员(字段)的类型,以保存引用并从此点使用它。这就是为什么您会在参数表达式列表中得到一个 MemberExpression

由于不能直接操作这个生成的类型,所以不能只使用成员表达式 Value 属性。但是您可以使用 MemberInfo 和目标引用(编译器生成类型的实例)动态调用成员访问器。

我不会依赖此代码。

您可以在此处阅读有关 lambda 相关编译器生成代码的更多信息,例如:http://thewalkingdev.blogspot.fr/2012/04/c-lambda-expressions-and-closures.html

关于c# - 获取对作为函数传递的 Lambda 中的参数的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21579900/

相关文章:

c# - 如何从并行运行中排除某些功能/场景?

c#如何循环遍历HttpRequestHeaders的所有 header

C# 如何确保用户提供线程安全对象来运行

java - 如果流包含多个逗号分隔值,则拆分流

接受谓词的 C# 方法 - 这看起来不错吗?

c# - 将 Visual Studio 2005 (C#) 连接到 Oracle8 最方便的方法是什么?

python - 在列表中创建函数

c# - C# Lambda 中的可变参数

ios - 在单独的类中使用 func() 需要拥有该方法的类的实例

c# - 在 Linq to Entities 和 Linq to Object 之间共享表达式