C#表达式树调用基类属性get方法

Han*_*ney 2 c# reflection expression-trees .net-4.5

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

public class A
{
    public string MyString {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

public class B : A
{

}
Run Code Online (Sandbox Code Playgroud)

如果我使用此表达式树代码(其中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() )
}
Run Code Online (Sandbox Code Playgroud)

我会收到这个例外:

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

我在这做错了什么?

Ser*_*nov 5

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

foreach (var property in properties)
{
    Expression.Property( 
         Expression.ConvertChecked( inputObject, property.DeclaringType ),
         property);
}
Run Code Online (Sandbox Code Playgroud)

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

UPDATE

对于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;
Run Code Online (Sandbox Code Playgroud)

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

UPDATE2

这是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; 
} 
Run Code Online (Sandbox Code Playgroud)

问题出在这一行:

if (method == propertyMethod) {
    return true; 
} 
Run Code Online (Sandbox Code Playgroud)

当您从Type获取GetGetMethod的MethodInfo时A,它与Type中的MethodInfo不同B,并且此检查返回false.这样的例子也返回false:

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

  • 这工作了,谢谢!如果你能告诉我为什么它有效,我会给你答案,因为我不理解,它让我不理解我的代码! (2认同)
  • `Expression.Property` 接受带有派生的 `ReflectedType` 的 `PropertyInfo`,但不接受带派生的 `MethodInfo` ,这似乎仍然是一个错误。 (2认同)