The easiest way to ask this is to show the example (LinqPad) code that demonstrates the issue at hand:
void Main()
{
GetProp<IFace>().DeclaringType.Dump(); // iface
GetProp<C>().DeclaringType.Dump(); // iface
GetProp().DeclaringType.Dump(); // c
}
public interface IFace { int A { get; set; } }
public class C : IFace { public int A { get; set; } }
public PropertyInfo GetProp<T>() where T : IFace
{
return ExtractProperty((T x) => x.A);
}
public PropertyInfo GetProp()
{
return ExtractProperty((C x) => x.A);
}
private PropertyInfo ExtractProperty<T, V>(Expression<Func<T, V>> exp)
{
return (PropertyInfo) ((MemberExpression) exp.Body).Member;
}
I am intrigued by why GetProp<C>
uses returns a property on IFace
instead of a property on C
. Can anyone explain this behavior? Looking at the IL code
, I can see that the generic version of GetProp<T>
uses ldtoken on the IFace
type, but why is it implemented this way? Can anyone point me to a justification or spec for this behavior?
Because member lookup is done at compile time.
The compiler binds x.A
in your lambda to the A
property in the interface.
This is specified in §7.4 of the spec:
A member lookup of a name N with K type parameters in a type T is processed as follows:
First, a set of accessible members named N is determined:
- If T is a type parameter, then the set is the union of the sets of accessible members named N in each of the types specified as a primary constraint or secondary constraint (§10.1.5) for T, along with the set of accessible members named N in object.