Lambda表达式未返回预期的MemberInfo

时间:2011-07-12 01:42:59

标签: c# lambda

我遇到了一个我没想到的问题。一个例子可能比段落更好地说明我的问题:

更新:跳到最后一个代码块,以获得更有说服力的代码示例。

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

public class C : A { }

以下是方法中的一些代码:

var a = typeof(C).GetMember("B")[0];
var b = typeof(A).GetMember("B")[0];

Expression<Func<C, string>> c = x => x.B;

var d = (c.Body as MemberExpression).Member;

以下是一些比较的结果:

a == b //false
a == d //false
b == d //true

前两个有些出乎意料。我知道即使B不是虚拟的,C也可以用w new运算符定义一个具有相同名称的属性,但在这种情况下我没有。

第二个对我来说真是最令人惊讶的(这是我问题的核心)。即使lambda的参数明确定义为C类型,它仍然返回它,就好像从基类访问属性一样。

我正在寻找的是一种从lambda表达式获取MemberInfo的方法,就好像我使用了对参数类型的反射来获取MemberInfo。我的项目实际上将MemberInfos存储在各种字典中,它需要具有可以通过提供lambda表达式来访问元素的功能。

Danny Chen重述的代码示例

public class Base
{
    public string Name { get; set; }
}
public class Derived : Base { }

//in Main
var parentMember = typeof(Base).GetMember("Name")[0];
var childMember = typeof(Derived).GetMember("Name")[0];

Expression<Func<Base, string>> parentExp = x => x.Name;
var parentExpMember = (parentExp.Body as MemberExpression).Member;

Expression<Func<Derived, string>> childExp = x => x.Name;
var childExpMember = (childExp.Body as MemberExpression).Member;

parentMember == childMember  //false, good
parentMember == parentExpMember  //true, good
childMember == childExpMember   //false, why?

4 个答案:

答案 0 :(得分:15)

获取表达式(第一个)参数的类型,并说出

Expression<Func<C, string>> c = x => x.B; 
Type paramType = c.Parameters[0].Type;  // first parameter of expression
var d = paramType.GetMember((c.Body as MemberExpression).Member.Name)[0];

答案 1 :(得分:10)

  

我正在寻找的是一种从lambda表达式获取MemberInfo的方法,就好像我使用了对参数类型的反射来获取MemberInfo。

这不是lambdas上的表达式树转换旨在提供的服务。 如果您要使用“off label”功能,那么您可能无法获得所需的结果。

表达式树的目的是以适合在运行时分析的形式提供编译器对表达式的语义分析,而不是为了构造可以远程访问数据库的查询对象而编译时间。

编译器的正确语义分析是Name在的实例上声明作为Base的属性并且调用,这正是您从中获取的信息结果表达式树。

答案 2 :(得分:6)

好问题。我使用其他一些名字来使它更清楚。

public class Base
{
    public string Name { get; set; }
}
public class Derived : Base { }

//in Main
var parentMember = typeof(Base).GetMember("Name")[0];
var childMember = typeof(Derived).GetMember("Name")[0];

Expression<Func<Base, string>> parentExp = x => x.Name;
var parentExpMember = (parentExp.Body as MemberExpression).Member;

Expression<Func<Derived, string>> childExp = x => x.Name;
var childExpMember = (childExp.Body as MemberExpression).Member;

parentMember == childMember  //false, good
parentMember == parentExpMember  //true, good
childMember == childExpMember   //false, why?

调试时,您会发现childExpMember.ReflectedTypeBase,而childMember.ReflectedTypeDerived。 AFAIK DeclaringType显示声明成员的位置,而ReflectedType显示成员被反映到的位置(因为继承/覆盖/等)。所以我认为这是一个错误(没有官方确认)。

答案 3 :(得分:2)

我相信你需要将标志“FlattenHierarchy”传递给GetMember的bindingAttr参数。

来自MSDN:

  

指定应返回层次结构中的公共和受保护静态成员。不返回继承类中的私有静态成员。静态成员包括字段,方法,事件和属性。不返回嵌套类型。