调用基类属性get方法的C#表达式树
我构建了一个表达式树,它从一个类中派生参数,并调用它们来设置另一个类中的值。它对大多数类型都很有效,但对派生类型无效。如果我有:调用基类属性get方法的C#表达式树,c#,reflection,.net-4.5,expression-trees,C#,Reflection,.net 4.5,Expression Trees,我构建了一个表达式树,它从一个类中派生参数,并调用它们来设置另一个类中的值。它对大多数类型都很有效,但对派生类型无效。如果我有: public class A { public string MyString {get; set;} } 及 如果使用此表达式树代码(其中value是派生实例): 我将收到此例外: {System.ArgumentException: The method 'My.Namespace.A.get_MyString' is not a property ac
public class A
{
public string MyString {get; set;}
}
及
如果使用此表达式树代码(其中value
是派生实例):
我将收到此例外:
{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);
}
基本上你需要使用这个,而不是这个
更新
对于getMethod方法-如果var objectType
等于A
类型,则该方法有效。如果它等于B
type,则它不起作用
我猜问题出在属性.DeclaringType
中。对于这两种情况,它都是类型,正如在其中声明的属性一样。但是对于相同的属性,此代码将返回不同的ReflectedType
:
var reflectingTypeForA = typeof(A).GetProperty("MyString").GetGetMethod().ReflectedType;
var reflectingTypeForB = typeof(B).GetProperty("MyString").GetGetMethod().ReflectedType;
对于A
它返回A
,对于B
类型它返回B
。我的猜测是,对于B
大小写表达式。属性逻辑检查属性。DeclaringType
是A
,但GetGetMethod的ReflectedType
等于B
,因此它认为它是另一个对象的属性。我没有任何证据证明这一点,但只有这些成员在两个getMethod调用之间是不同的
更新2
以下是Expression.Property(MethodInfo方法)使用的代码:
问题出在这一行:
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
这成功了,谢谢!我会给你答案,如果你能告诉我为什么它有效,因为我不理解,不理解我的代码会让我痛苦!把我的猜测加入到答案中:)该死,答案很棒。谢谢@Sergey-非常感谢。我想知道这在技术上是否是.NET framework中的一个bug?从技术上讲,这两个对象是不同的,因为ReflectedType。所以,这不是一个错误。以下是Jon Skeet给出的关于ReflectedType的答案-我不同意他们关于ReflectedType
的设计决策,但至少现在我明白了为什么我的代码会被破坏。:)
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;
}
var propertyAGetter = typeof(A).GetProperty("MyString").GetGetMethod();
var propertyBGetter = typeof(B).GetProperty("MyString").GetGetMethod();
bool areTheSame = propertyAGetter == propertyBGetter; // it equals to false