C# Expression Tree调用基类属性get方法

标签 c# reflection .net-4.5 expression-trees

我构建了一个表达式树,它从一个类派生参数并调用它们来设置另一个类中的值。它适用于大多数类型,但不适用于派生类型。如果我有:

public class A
{
    public string MyString {get; set;}
}

public class B : A
{

}

如果我使用此表达式树代码(其中 value 是派生实例):

// Get the type of the object for caching and ExpressionTree purposes
var objectType = value.GetType();
// Define input parameter
var inputObject = Expression.Parameter( typeof( object ), "value" );

var properties = objectType.GetProperties( BindingFlags.Instance | BindingFlags.Public );
foreach (var property in properties)
{
    Expression.Property( Expression.ConvertChecked( inputObject, property.DeclaringType ), property.GetGetMethod() )
}

我会收到这个异常:

{System.ArgumentException: The method 'My.Namespace.A.get_MyString' is not a property accessor
at System.Linq.Expressions.Expression.GetProperty(MethodInfo mi)...

我在这里做错了什么?

最佳答案

您需要使用属性本身而不是 Getter 方法:

foreach (var property in properties)
{
    Expression.Property( 
         Expression.ConvertChecked( inputObject, property.DeclaringType ),
         property);
}

基本上你需要使用这个Property method而不是这个重载 Property method

更新

对于 GetGetMethod 方法 - 如果 var objectType 等于 A 类型,则它有效。如果它等于B 类型,则它不起作用。

我猜,问题出在 property.DeclaringType 中。对于这两种情况,它都是 A 类型,作为其中声明的属性。但是此代码将为同一属性返回不同的 ReflectedType:

var reflectingTypeForA = typeof(A).GetProperty("MyString").GetGetMethod().ReflectedType;
var reflectingTypeForB = typeof(B).GetProperty("MyString").GetGetMethod().ReflectedType;

对于A,它返回A,对于B,它返回B。我的猜测是,对于 B 情况,Expression.Property 逻辑检查 property.DeclaringType 是否为 A,但 GetGetMethod 具有 ReflectedType 等于 B,所以它认为它是另一个对象的属性。我没有任何证据,但只有这些成员在两次 GetGetMethod 调用之间不同

更新 2

这是 Expression.Property(MethodInfo 方法)使用的代码:

private static PropertyInfo GetProperty(MethodInfo mi)
{
    Type type = mi.DeclaringType;
    BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic;
    flags |= (mi.IsStatic) ? BindingFlags.Static : BindingFlags.Instance;
    PropertyInfo[] props = type.GetProperties(flags);
    foreach (PropertyInfo pi in props)
    {
        if (pi.CanRead && CheckMethod(mi, pi.GetGetMethod(true)))
        {
            return pi;
        }
        if (pi.CanWrite && CheckMethod(mi, pi.GetSetMethod(true)))
        {
            return pi;
        }
    }
    throw new SomeException();
}

private static bool CheckMethod(MethodInfo method, MethodInfo propertyMethod) { 
    if (method == propertyMethod) {
        return true; 
    } 
    // If the type is an interface then the handle for the method got by the compiler will not be the
    // same as that returned by reflection. 
    // Check for this condition and try and get the method from reflection.
    Type type = method.DeclaringType;
    if (type.IsInterface && method.Name == propertyMethod.Name && type.GetMethod(method.Name) == propertyMethod) {
        return true; 
    }
    return false; 
} 

问题出在这一行:

if (method == propertyMethod) {
    return true; 
} 

当您通过 GetGetMethod 从类型 A 获取 MethodInfo 时,它不同于从类型 B 获取 MethodInfo,并且此检查返回 false。 这样的例子也返回 false:

var propertyAGetter = typeof(A).GetProperty("MyString").GetGetMethod();
var propertyBGetter = typeof(B).GetProperty("MyString").GetGetMethod();
bool areTheSame = propertyAGetter == propertyBGetter; // it equals to false

关于C# Expression Tree调用基类属性get方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21096557/

相关文章:

c# - 为什么 ListView 会触发事件,指示添加后未选中选中的项目

c# - Linq,将多个记录组合成逗号分隔的字符串,按不同值分组

c# - 允许或禁止方法在 .NET 中运行

c# - 在 .Net 中使用私有(private)集初始化属性

c# - 网站中静态变量的奇怪行为

c# - SignalR 类型名称处理

c# - 加载/卸载 C dll 时出现 C# 问题

c# - 最好的 NHibernate 缓存 L2 提供程序是什么?

java - ExceptionInInitializerError : code size limit exceeded when loading a DLL in JNA

c# - 使用 .NET 框架读取串口的正确方法是什么?