如何从一个前pression小孩声明类型? [英] How to get the child declaring type from an expression?

查看:125
本文介绍了如何从一个前pression小孩声明类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个父/子类层次结构中的父抽象声明一个字符串属性和子类实现它:

 抽象类的父
{
   公共抽象的字符串值{获得; }
}

类儿童:父母
{
   公众覆盖字符串值{{返回NULL; }}
}
 

当我使用显式(或隐式)使用儿童类的EX pression,我想到了前pressions的的MemberInfo的DeclaringType是'孩子',而是它是父:

 孩童=新的儿童();
防爆pression< Func键<字符串>> EX pression =(()=> child.Value);
的MemberInfo的MemberInfo = EX pression.GetMemberInfo();
Assert.AreEqual(typeof运算(儿童),memberInfo.DeclaringType); //方式无法!
 

断言失败,因为DeclaringType是家长。

有什么我可以宣布我的前pression或消费它揭示了实际使用的儿童型的呢?

注:GetMemberInfo()按照上述的扩展方法(我甚至忘了我们这样写的!):

 公共静态类TypeExtensions
{
    ///<总结>
    ///获取再由EX pression psented $ P $的会员资料。
    ///< /总结>
    ///< PARAM NAME =EX pression>成员EX pression< /参数>
    ///<返回>再由EX pression pseted $ P $的会员资料< /回报>
    公共静态的MemberInfo GetMemberInfo(此例pression EX pression)
    {
        VAR的λ=(LambdaEx pression)EX pression;

        MemberEx pression memberEx pression;
        如果(lambda.Body是UnaryEx pression)
        {
            VAR unaryEx pression =(UnaryEx pression)lambda.Body;
            memberEx pression =(MemberEx pression)unaryEx pression.Operand;
        }
        其他memberEx pression =(MemberEx pression)lambda.Body;

        返回memberEx pression.Member;
    }
}
 

解决方案

没有 - 这是将要由C#编译器发出的一个准确的重新presentation。该倍率有效地忽略寻找成员时 - 编译器只在乎原来的声明的成员类型。您可以通过编译code,然后在看IL看到这样的自己。这个方法:

 静态无效的主要()
{
    Child C级=新的儿童();
    字符串x = c.Value;
}
 

被编译成这个IL:

  IL_0000:NOP
IL_0001:newobj实例无效儿童::构造函数()
IL_0006:stloc.0
IL_0007:ldloc.0
IL_0008:callvirt比如字符串家长::的get_value()
IL_000d:stloc.1
IL_000e:RET
 

有一点琐事:VB编译器的的工作方式相同,因此这种方法:

 公共共享小组主(参数为String())
    昏暗x As中儿童=新的​​儿童()
    Ÿ暗淡作为字符串= x.Value
结束小组
 

被编译为:

  IL_0000:newobj实例无效[库]儿童::构造函数()
IL_0005:stloc.0
IL_0006:ldloc.0
IL_0007:callvirt比如字符串[库]儿童::的get_value()
IL_000c:stloc.1
IL_000d:RET
 

I have a Parent / Child class hierarchy where the Parent abstractly declares a string property and the Child class implements it:

abstract class Parent
{
   public abstract string Value { get; }
}

class Child : Parent
{
   public override string Value { get { return null; } }
}

When I use an expression that explicitly (or implicitly) uses the Child class, I expect the Expressions's MemberInfo's DeclaringType to be 'Child', but instead it is Parent:

Child child = new Child();
Expression<Func<string>> expression = (() => child.Value);
MemberInfo memberInfo = expression.GetMemberInfo();
Assert.AreEqual(typeof(Child), memberInfo.DeclaringType); // FAILS!

The assertion fails because the DeclaringType is Parent.

Is there something I can do in declaring my expression or consuming it to reveal the actual use of the Child type?

NOTE: GetMemberInfo() above as an extension method (I even forgot we had written this!):

public static class TypeExtensions
{
    /// <summary>
    /// Gets the member info represented by an expression.
    /// </summary>
    /// <param name="expression">The member expression.</param>
    /// <returns>The member info represeted by the expression.</returns>
    public static MemberInfo GetMemberInfo(this Expression expression)
    {
        var lambda = (LambdaExpression)expression;

        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = (UnaryExpression)lambda.Body;
            memberExpression = (MemberExpression)unaryExpression.Operand;
        }
        else memberExpression = (MemberExpression)lambda.Body;

        return memberExpression.Member;
    }
}

解决方案

No - this is an accurate representation of what gets emitted by the C# compiler. The override is effectively ignored when looking for the member - the compiler only cares about the type that originally declared the member. You can see this for yourself by compiling code and then looking at the IL. This method:

static void Main()
{
    Child c = new Child();
    string x = c.Value;
}

is compiled into this IL:

IL_0000:  nop
IL_0001:  newobj     instance void Child::.ctor()
IL_0006:  stloc.0
IL_0007:  ldloc.0
IL_0008:  callvirt   instance string Parent::get_Value()
IL_000d:  stloc.1
IL_000e:  ret

One point of trivia: the VB compiler doesn't work the same way, so this method:

Public Shared Sub Main(Args As String())
    Dim x As Child = New Child()
    Dim y As String = x.Value
End Sub

is compiled as:

IL_0000:  newobj     instance void [lib]Child::.ctor()
IL_0005:  stloc.0
IL_0006:  ldloc.0
IL_0007:  callvirt   instance string [lib]Child::get_Value()
IL_000c:  stloc.1
IL_000d:  ret

这篇关于如何从一个前pression小孩声明类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆