嘗試為 Expression 類別撰寫擴充方法以簡化 Lambda 運算式建構,卻遇到莫名其妙的編譯錯誤:
Member '...TestMethod()' cannot be accessed with an instance reference; qualify it with a type name instead
錯誤原因:擴充方法與被擴充類別的靜態方法同名同簽名。編譯器誤以為呼叫實例方法的是靜態方法,而拒絕編譯。
public class A { public static void Method() { } }
public static class AExt { public static void Method(this A a) { } }
static void Main() {
var a = new A();
a.Method(); // 編譯失敗!錯誤 CS0176
}
只要註解掉 a.Method() 即可編譯通過。繼承類別同樣受影響:class B : A 的擴充方法 Method(this B b) 也會因 A.Method() 存在而失效。
擴充方法本質是靜態方法,語法糖讓我們像呼叫實例方法。但編譯器解析呼叫時,優先檢查型別本身的靜態成員,發現同名靜態方法即報錯,不再考慮擴充方法。這與「同一類別不可有同簽名靜態/實例方法」的規則一致,但擴充方法屬於不同類別,理應不衝突。
// 想寫的擴充方法
public static MemberExpression Property(this Expression expr, string name) { ... }
// Expression 內建靜態方法
public static MemberExpression Property(Expression expr, string name) { ... }
// 呼叫時
var expr = ...;
expr.Property("Name"); // 編譯錯誤!
Expression.Property(expr, "Name"); // 正常
被迫改名(如 GetProperty),犧牲了語義一致性。
截至發文,仍懷疑此為編譯器缺陷而非設計使然,期待社群進一步分析。