2012-05-16 53 views
1

在下面的代碼中,我定義了兩個重載的方法,名爲Bar。在Foo()中,我撥打了Bar三個電話,並在第三個電話上發生錯誤。帶參數數組的泛型C#方法重載解析

前兩項解決了預期的重載問題。然而該第三生成以下錯誤:

The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Bar<T>(T, string, params object[])'. There is no implicit reference conversion from 'string' to 'System.Exception'.

顯然,第三呼叫「()欄」結合,但不能與第一參數轉換爲異常。同樣清楚的是,它是第二個參數是一個拋出編譯器的字符串。當它不是字符串(情況2)時,分辨率很好。但對我來說,看起來很明顯,失敗的行應該綁定到「Bar()」(因爲第一個參數明確地是一個字符串)。

任何人都可以解釋爲什麼編譯器使用此綁定?我會考慮創造性的解決方法,但我真正想要的是解釋爲什麼會發生這種情況。我花了一些時間用C#語言規範,但沒有找到(即放棄)明確的答案。很明顯,我可以重新命名Bar方法之一,或提供命名參數,或者標記參數ref之一......但這些都不適合我的特定場景。

不是說它是相關的,但我已經編寫了完全這樣的Java代碼,並且編譯器沒有問題。

代碼:

public void Bar(string s, params object[] ps) { } // Call this "Bar()" 
public void Bar<E>(E e, string s, params object[] ps) where E : Exception { } // Call this "Bar<T>()" 

public void Foo() 
{ 
    Exception e; 
    Object o1, o2; 

    Bar(e, "fmt {0}", o); // Resolves fine, as expected 
    Bar("fmt {0} {2}", o1, o2); // Also resolves as expected 
    Bar("fmt {0} {2}", "bar", o1); // Error! 
} 
+0

類似於:http://stackoverflow.com/questions/965423/c-sharp-generic-overload-compiler-cant-determine-correct-call – Travis

+0

但這個問題正在處理一個模棱兩可的問題。在這種情況下,編譯器和我同意有一個綁定,我們只是不同意哪一個! – pamphlet

回答

4

答案是過載匹配不考慮約束。至於C#規範中的這一點,我並不完全確定。匹配總是使用最具體的選項和字符串作爲通用T始終比字符串更具體Object(因爲它匹配實際類型而不是子類型)。請參閱Eric Lippert博客上的Constraints are not part of the signature

爲了使這項工作,如果需要例外的約束,如果可能的話使用void Bar(Exception E, ...)

+0

關於被忽略的約束,這很有趣。但是,第一個參數是不是一個字符串使非泛型更好匹配?我的意思是,它綁定到導致失敗的方法,而不是一個不會的方法。你知道嗎? – pamphlet

+1

由於第一個「Bar」的第二個參數是一個可選對象,因此匹配第二個參數更具體。 'Bar(字符串作爲T,字符串,...)'比'Bar(字符串,字符串作爲Object,...)'更具體。我想你可以用另一種方式來考慮,但編譯器團隊是以第一種方式寫的。 Eric Lippert(http://blogs.msdn.com/b/ericlippert/)可能有話要說這是什麼情況。帶「T」的字符串比「Object」字符串更具體。 – Travis

+3

@Travis看起來像他。 http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx – climbage

2

Bar("fmt {0} {2}", "bar", o1); //錯誤! 通過特殊優先級,它查找方法簽名,其中第二個參數是字符串(字符串比對象更具體),然後嘗試解析類型參數,但它不能。爲了說明這一點,嘗試將第三個呼叫替換爲:

Bar("fmt {0} {2}", (object)"bar", o1); // Now it is fine for compiler!