別著了 型別推斷 的道

2022-03-24 13:46:42 字數 1856 閱讀 1226

自打.net出了泛型之後,型別推斷(type inference)就變得愈加強大。比如下面的**:

//常規泛型方法

var tuple1 

=tuple.create

<

int, 

string

>

(2012, "

二零一二");

//泛型方法的自動型別推斷(編譯時)

var tuple2 

=tuple.create(

2012, "

二零一二");

以前需要定義泛型方法的引數型別,在基於編譯時的型別推斷系統的幫助下,立馬簡化為第二種寫法。大大的提高了開發效率。

可是自動型別推斷偶爾也會導致一些隱藏很深的bug出現。讓我們先看一下下面的**:

class

foovoid

execute(ienumerable

<

string

>

list)

void

execute

<

t>

(t anotherarg)

}這個物件中,我們定義了兩個方法,乙個是常規方法,其要求傳入乙個型別為ienumerable的引數。另外乙個則是乙個泛型方法,其接受乙個型別為t的引數。

在主方法體中,我們構造了乙個list,並呼叫execute方法。我想你也許會期望其呼叫的是第乙個方法。但是如果將這段**執行後,會發現編譯器在編譯時,通過型別推斷,自動幫你鏈結到了第二個泛型方法的呼叫上。這是因為編譯器針對方法呼叫的繫結流程,是基於如下的優先順序:

2)型別推斷

3)過載決策

型別推斷在方法呼叫

的繫結時處理過程中進行,發生在呼叫的過載決策步驟之前。當在方法呼叫中指定了特定的方法組,並且沒有在方法呼叫中指定型別實參時,將會對該方法組中的每個泛型方法應用型別推斷。如果型別推斷成功,則使用推斷出的型別實參確定用於後續過載解析的實參的型別。如果過載決擇選擇乙個泛型方法作為要呼叫的方法,則使用推斷出的型別實參作為用於呼叫的實際型別實參。如果特定方法的型別推斷失敗,則該方法不參與過載決策。型別推斷失敗本身不會導致繫結時錯誤。但是,當過載決策未能找到任何適用的方法時,它通常會導致繫結時錯誤。

上面就是型別推斷流程在編譯期對當前類呼叫方法的鏈結過程。那麼針對基類方法,其處理過程又是如何?

class

foo : parent

void

execute(ienumerable

<

string

>

list)

void

execute

<

t>

(t anotherarg)

}class

parent

}從剛才的執行優先順序上我們可以知道,正對當前類,如果簽名一致的話,則會呼叫此方法。在上面的**中,基類定義了乙個方法,其簽名和子類的呼叫簽名是一致的,但是當我們執行這段**會發現,方法實際上鏈結到了子類的execute泛型方法體上。因此,上述的鏈結優先順序,對基類方法不起作用。

當然,如果你將方法的呼叫前面加入base.execute關鍵字,則一定會進入到基類的方法體中。

最後,說一下個人感覺:

1)型別推斷是好東西,應該頂。不過要慎用,尤其是方法過載比較多的情況下。

2)編譯器在方法鏈結的過程中,針對泛型方法其優先順序還是比較高的,因此如果出現多個方法過載,且包括泛型的情況下,一定要多點小心。

3)如果自己明確的清楚自己要呼叫的方法是處於基類時,最後能夠加入base關鍵字,以避免不必要的問題。當然,如果你已經對.net游刃有餘,當然不必。

4)專案**最終是要交給別人維護的,如果希望自己能早日甩掉這個攤子去玩些新東西,就最好能夠寫出讓維護者一目了然的**,否則永遠甩不掉(扯遠了 -_-!!)

5 4 3 值的型別推斷

5.4.3 值的型別推斷 一般情況下,型別推斷是一種機制,從 推斷出型別。其目的為了簡化 消除了顯式指定所有型別的需要。在本節中,我們會看到值的型別推斷,使建立值更容易,不需要寫出它們的型別。這並不是型別推斷出現的唯一地方 尤其是在 f 中 這是描述型別推的斷第一部分。我們將在下一章中討論函式 和方...

泛型之型別引數的型別推斷

編譯器判斷型別方法的實際型別引數的過程稱為型別推斷,型別推斷是相對於知覺推斷的,其實現方法是一種非常複雜的過程.根據呼叫泛型方法時實際傳遞的引數型別或返回的型別來推斷,具體規則如下 swap new string 2 2,3 static void swap e a,int i,int j add ...

5 4 3 1 C 3 0 中的型別推斷

5.4.3.1 c 3.0 中的型別推斷 在 c 中,值型別推斷主要用 var 關鍵字表示,這是 c 3.0 的新功能。我們前面已經看到,但通過清單 5.12 的幾個例子,我們可以更詳細地討論一下。清單 5.12 使用 var 關鍵字進行型別推斷 c var num 10 2 16 var str ...