我已经构建了一个表达式树,它从类派生参数并调用它们来设置另一个类中的值。它适用于大多数类型,但在派生类型上失败。如果我有:
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)...
我在这里做错了什么?
答案 0 :(得分:5)
您需要使用属性本身而不是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
,所以它认为它是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;
}
另一个物体的财产。我没有任何证明,但只有这两个成员在两个GetGetMethod调用之间是不同的
<强> UPDATE2 强>
这是Expression.Property(MethodInfo方法)使用的代码:
if (method == propertyMethod) {
return true;
}
问题出在这一行:
A
当您从类型B
通过GetGetMethod获取MethodInfo时,它与类型var propertyAGetter = typeof(A).GetProperty("MyString").GetGetMethod();
var propertyBGetter = typeof(B).GetProperty("MyString").GetGetMethod();
bool areTheSame = propertyAGetter == propertyBGetter; // it equals to false
中的MethodInfo不同,并且此检查返回false。
这样的例子也返回false:
{{1}}