c# - 从方法表达式获取具体类型

标签 c# expression-trees

如果我有一个 Expression<Func<Delegate>> 形式的表达式是否可以确定用于传递委托(delegate)的对象的派生类型?该表达式是否包含此信息,或者它是否唯一代表委托(delegate)。

代码示例应该会让事情变得更清楚。

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Sandbox {

    public interface IContract {
        void Method();
    }

    public class Concrete : IContract {
        public void Method() { }
    }

    public class Test {

        private IContract contract = new Concrete();
        private Concrete concrete = new Concrete();

        public static string GetFullMethodName(Expression<Func<Action>> expression) {
            var unaryExpression = (UnaryExpression)expression.Body;
            var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;

            var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last();
            var methodInfo = (MemberInfo)methodInfoExpression.Value;

            var type = methodInfo.DeclaringType;
            var name = methodInfo.Name;

            return String.Format("{0}.{1}", type, name);
        }

        public Test() {
            var strConcrete = GetFullMethodName(() => concrete.Method); // Sandbox.Concrete.Method
            var strContract = GetFullMethodName(() => contract.Method); // Sandbox.IContract.Method
        }

    }

}

是否可以制作 () => contract.Method生产

Sandbox.Concrete.Method

而不是

Sandbox.IContract.Method

是否可以更改表达式以支持这一点,或者我是否会被迫将对象的实例作为单独的参数传递以确定其类型?

最佳答案

不,这是不可能的。

表达式树是根据编译时信息构建的,在编译时,被调用的方法是虚拟的IContract.Method。事实上,在运行时,Concrete.Method 实际被调用是无关紧要的 - 这是在虚拟调度机制中处理的,并且编译器早在任何决定之前就完成了它的工作。

您能做的最好的事情就是尝试自己模拟虚拟调度。例如,您可以尝试在运行时枚举 this 实例上的接口(interface)实现,如果您确实找到与该接口(interface)匹配的方法,则将返回该方法。然而,这确实很棘手 - 您需要能够完美模拟实际的虚拟调度。

另一个棘手的问题是你尝试获取值的方式已经被破坏了。例如,在我的环境中,methodInfoExpression不是一个ConstantExpression - 它是闭包类型上的一个字段。你的“解析”非常脆弱。

也就是说,这也是不必要和过于复杂的 - 您试图接收一个返回操作的表达式,并从表达式中“窃取”操作的值。已经有一个简单的方法可以做到这一点 - 直接传递该参数。无需将其隐藏在表达式树中:

public static string GetFullMethodName(Action action)
{
  return string.Format("{0}.{1}", action.Method.DeclaringType.Name, action.Method.Name);
}

var strConcrete = GetFullMethodName(concrete.Method).Dump(); // Sandbox.Concrete.Method
var strContract = GetFullMethodName(contract.Method).Dump(); // Sandbox.Concrete.Method

你不需要表达基本反射已经给你的东西:)

关于c# - 从方法表达式获取具体类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36862237/

相关文章:

c# - 如何将表达式编译成实际结果?

c# - 将 GUID 转换为长

C# 为什么 form.Close() 不关闭表单?

c# - Signalr 无法连接远程服务器

c# - 密码保护的 OpenXml Word 文档重新保存为密码保护的二进制 Word

c# - LINQ 表达式中不区分大小写的字符串比较

c# - "IntConverter"的实例存储在哪里?

c# - 使用 Irony 实现前缀表示法表达式解析器

c# - Specflow/自动化测试 - 使目录无法访问

C# 在 lambda 表达式中切换