Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
303 views
in Technique[技术] by (71.8m points)

c# - How to get the child declaring type from an expression?

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;
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...