从成员表达式中获取反射类型

9

考虑以下代码:

static void Main(string[] args)
{
    Expression<Func<SomeDerivedClass, object>> test = i => i.Prop;
    var body = (UnaryExpression) test.Body;
    Console.WriteLine(((MemberExpression) body.Operand).Member.ReflectedType);
}

public class SomeClass
{
    public int Prop { get; private set; }
}

public class SomeDerivedClass : SomeClass
{
}

我原本期望ReflectedType会是SomeDerivedClass,因为它是表达式参数的类型。但实际上它是SomeClass,如果我理解正确的话,这是声明类型。
为什么会这样呢?
3个回答

5
表达树的构建细节大多没有具体说明。唯一要注意的是,表达树必须对应于用于构建表达树的C#语法。在普通的C#表达式中,只有相当于DeclaringType的内容被编码进了IL中。该成员根本没有通过反射进行访问,因此不需要考虑ReflectedType。由于没有ReflectedType可考虑,两个不同的PropertyInfo对象同样适用于原始源代码。
作为一个潜在的原因,考虑这个略微邪恶的派生类:
public class SomeClass
{
    public int Prop { get; set; }
}

public class SomeDerivedClass : SomeClass
{
    public int get_Prop() { return 4; }
}

这里,基类的 Prop getter 方法没有被覆盖,但原始的 get_Prop 属性编译器生成的 getter 函数只能通过基类访问。因此,Prop 的唯一正确的属性 getter 是 SomeClass.get_Prop,即使在已知静态对象为 SomeDerivedClass 的情况下,也不应使用 SomeDerivedClass.get_Prop
再加上 C# 编译器自动生成的代码内部构建表达式树时,通过获取属性 getter 方法并请求运行时查找相应的 PropertyInfo 对象来获得适当的 PropertyInfo 对象,你就可以得到答案:必须从 SomeClass 获取属性 getter 方法,因此也会从 SomeClass 中获取 PropertyInfo

谢谢您的回答,我误解了问题。刚刚运行了代码,确实是一样的。 - Andrew
你也可以使用virtual基属性来说明这一点。使用override关键字,你会得到SomeClass。然而,使用(丑陋的)new关键字,你会得到SomeDerivedClass - l33t

2
那是因为表达式评估为Prop,它在SomeClass中定义而不是SomeDerivedClass。请注意,SomeDerivedClass仅是您的test lambda参数的类型,因此它与其主体的类型无关,其主体是访问位于SomeClass中的属性的UnaryExpression
还可以将Prop添加到SomeDerivedClass中,然后您将获得预期的结果。

如果基属性是“虚拟的”,并且您“覆盖”它,则无法工作。 - l33t

-1

你误解了问题。OP说ReflectedType是基础类型,而他希望它是子类类型,我已经根据文档解释了为什么反射类型是声明成员的类型。 - Andrew
2
DeclaringType 总是声明成员的类型,这就是为什么它被称为 DeclaringType。在 OP 的情况下,DeclaringTypeReflectedType 都将是 SomeClass - user743382

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接