2012-05-04 54 views
8

我有這樣的功能:運算符與C#動態?

static void Func1<T>(T x, T y) 
{ 
    dynamic result = ((dynamic)x + y); //line 1 
    dynamic result2 = (x + y);   //line 2 
} 

Func(1,2);然而,線1是本功能可被執行,而線2進入BANG(在編譯時間)。

從2號線引發的異常是:

操作「+」不能應用於類型「T」的操作數和「T」

所以,我們需要創建一個運營商超載。好的,到目前爲止這麼好。

但是第1行呢?它不應該也需要y上的動態演員陣容嗎?

((dynamic)x + (dynamic)y);

我明白這是在運行時進行評估,但爲什麼C#編譯器接受1號線的運營商+(即錯誤地認爲,T可以+別的東西)?

+0

執行代碼後'result'中的值是多少?是'3'還是'12'。我的猜測是它正在做字符串連接。 – Servy

+1

@Servy:當'T'是'int'時,是什麼讓你認爲它會進行字符串連接? – LukeH

回答

7

在您的第一個示例中,通過使x a dynamic您實際上也使operator+操作變爲動態。這爲x擺脫了類型說明符T,從而擺脫了T沒有有效operator+的投訴。

在運行時動態結合將發生和評估兩個操作數,以確保operator+可用於:

如果算術運算符的操作數具有編譯時類型動態,則表達式是動態綁定的(第7.2.2節)。在這種情況下,表達式的編譯時類型是動態的,下面描述的分辨率將在運行時使用編譯時類型爲動態的操作數的運行時類型進行。

在第二個示例中,編譯器知道該類型x + y和簡單並將結果存儲到一個變量dynamicresult2的進一步用法將被動態綁定。這是有意義的,因爲沒有動態操作到賦值運算符的右

當沒有動態表達式都參與,C#默認爲靜態綁定,這意味着,組成表達式的編譯時類型是用於選擇過程。

+0

另外,我不得不想知道爲什麼你會使一個通用的方法嘗試使用沒有約束的類型特定的操作符。 – Tejs

+0

那麼,對於類似數字類型的東西,你不能拿出任何允許算術運算的類型約束。 – user7116

+0

我認爲首選的方法就是爲像框架那樣的特定值類型進行重載。否則,如果您想讓特定類型執行某種類型的操作,請使它們實現特定的接口,然後限制到該接口。 – Tejs

3

dynamic基本上告訴編譯器「不要試圖確定我在做什麼是合法的,我相信它會在運行時」。您嘗試對動態類型變量進行的任何操作都將被編譯。如果分配給動態變量的類型實際上沒有實現該操作,它將不會成功運行。

至於爲什麼它們都不必是動態的,編譯器基本上會試圖找到一個操作符(靜態方法),該操作符涉及與簽名匹配的操作中的任一類型,從LValue開始。在LValue是動態的情況下,編譯器必須假定該操作存在於任何將用作X的任何東西上,即使X與Y的佔位符類型相同且Y未知有+運算符。