2014-02-26 70 views
4

問這個最簡單的方法是要表明,在手演示問題的例子(LinqPad)代碼:爲什麼泛型類型的表達式引用約束類型而不是運行時類型?

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; 
} 

我明白爲什麼GetProp<C>使用收益上IFace而不是在C性質的性質很感興趣。誰能解釋這種行爲?看看IL code,我可以看到GetProp<T>的通用版本在IFace類型上使用ldtoken,但它爲什麼以這種方式實現?任何人都可以指出我對此行爲的理由或規範嗎?

回答

4

因爲成員查找是在編譯時完成的。

編譯器將您的lambda中的x.A綁定到接口中的A屬性。

這是在規範中的§7.4指定:

在類型T具有K個類型的參數的名稱N的成員查找的處理過程如下:

  • 首先,可訪問成員的組命名N被確定:

    • 如果T是一個類型參數,則該組是集合中的每個類型的名爲N可訪問成員的並集s被指定爲T的主要約束或次要約束(§10.1.5),以及對象中名爲N的可訪問成員集合。
+0

_ 「名爲N對象」 _ - 什麼對象? –

+0

@RoyiNamir:類型'System.Object'。 – SLaks