How to get the ad type of an ad from an expression?

I have a parent / child class hierarchy, where the parent abstractly declares a row 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 MemberInfo DeclaringType expression 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 statement fails because DeclaringType is the parent.

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

NOTE: GetMemberInfo () is above as an extension method (I even forgot that we wrote it!):

 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; } } 
+8
c # lambda linq
source share
3 answers

No is an accurate representation of what the C # compiler emits. Overrides are effectively ignored when searching for a member — the compiler only cares about the type that the member originally declared. You can see it for yourself by compiling the code and then looking at IL. This method:

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

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 small point: the VB compiler does not work that 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 

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 
+8
source share

My solution, based on information from @JonSkeet and @CodeInChaos, is not to not look exclusively at the PropertyInfo in the expression, but also at the Member MemberExpression Member:

 /// <summary> /// Extracts the PropertyInfo for the propertybeing accessed in the given expression. /// </summary> /// <remarks> /// If possible, the actual owning type of the property is used, rather than the declaring class (so if "x" in "() => x.Foo" is a subclass overriding "Foo", then x PropertyInfo for "Foo" is returned rather than the declaring base class PropertyInfo for "Foo"). /// </remarks> /// <typeparam name="T"></typeparam> /// <param name="propertyExpression"></param> /// <returns></returns> internal static PropertyInfo ExtractPropertyInfo<T>(Expression<Func<T>> propertyExpression) { if (propertyExpression == null) { throw new ArgumentNullException("propertyExpression"); } var memberExpression = propertyExpression.Body as MemberExpression; if (memberExpression == null) { throw new ArgumentException(string.Format("Expression not a MemberExpresssion: {0}", propertyExpression), "propertyExpression"); } var property = memberExpression.Member as PropertyInfo; if (property == null) { throw new ArgumentException(string.Format("Expression not a Property: {0}", propertyExpression), "propertyExpression"); } var getMethod = property.GetGetMethod(true); if (getMethod.IsStatic) { throw new ArgumentException(string.Format("Expression cannot be static: {0}", propertyExpression), "propertyExpression"); } Type realType = memberExpression.Expression.Type; if(realType == null) throw new ArgumentException(string.Format("Expression has no DeclaringType: {0}", propertyExpression), "propertyExpression"); return realType.GetProperty(property.Name); } 
+3
source share

If you do not need a static type method that you are working on, but rather a last override, then this is possible. I have not tested, but something similar to the following should execute:

 public bool FindOverride(MethodInfo baseMethod, Type type) { if(baseMethod==null) throw new ArgumentNullException("baseMethod"); if(type==null) throw new ArgumentNullException("type"); if(!type.IsSubclassOf(baseMethod.ReflectedType)) throw new ArgumentException(string.Format("Type must be subtype of {0}",baseMethod.DeclaringType)); while(true) { var methods=type.GetMethods(BindingFlags.Instance| BindingFlags.DeclaredOnly| BindingFlags.Public| BindingFlags.NonPublic); var method=methods.FirstOrDefault(m=>m.GetBaseDefinition()==baseMethod)) if(method!=null) return method; type=type.BaseType; } } 

Where you pass MemberInfo as the first parameter, and the runtime type of the object is the second. Note that this is probably slow, so you can add some caching.

+1
source share

All Articles