泛型不是模板

2022-02-24 05:14:11 字數 1644 閱讀 9842

譯自eric lippert's blog, 原文: 

因為我不是常人, 所以我喜歡去了解容易混淆的東西間的微妙差別:

我想我可以為程式語言設計中一些容易困惑的概念做乙個小系列.

這裡是乙個我經常遇到的問題:

code

public

class

cprivate

static

void

reallydoit(

string

s)private

static

void

reallydoit

<

t>

(t t)

當你呼叫c.doit會發生什麼呢?很多人希望列印出「string」, 然而不管t是什麼,事實上總是列印出「everything else」。

c#語言標準說當你需要面臨選擇呼叫reallydoit(string)或是reallydoit(string)的時候,也就是說在需要從兩個相同簽名方法選擇, 其中包含乙個是泛型方法的時候,我們會選擇非泛型的方法而不是泛型的方法。但在這裡我們為什麼不這麼做呢?

因為那不是標準所說的選擇。如果你說要呼叫reallydoit("hello world");

那麼我們會選擇非泛型的版本。但是你並不是把編譯器所知道的string型別進行引數傳遞。你只是傳遞了型別t,乙個沒有約束的型別引數,所以它可以是任何型別。所以由於過載決議的演算法,有沒有乙個方法能接收任何型別作為引數呢?回答是有。

這個c#裡泛型的例子並不像c++裡面的模板。你可以把模板想象成乙個奢華的搜尋替代的機制。當你說你要在模板中呼叫doit, 編譯器會概念性地搜尋出所有用到的「t」,再把它們替換成「string」 ,接著再編譯源**。過載決議用替代的已知型別引數來執行,生成的**也反映了過載決的結果。

泛型可不是這麼工作的。泛型是這樣的,好吧,一般的。我們只做一次過載決議然後固定了結果。當任何程式從乙個完全不同的程式集用string作為型別引數呼叫到這個方法的時候,我們不會在執行時改變它。我們為泛型生成的il**已經定好了將要去選出呼叫的方法。那個jit並不是說「好吧,如果我們讓c#編譯器用這個額外資訊去馬上執行我碰巧就知道了,那麼它就會挑乙個不同的過載. 讓我重寫一下生成的(il)**吧,讓編譯器忽略以前生成的」。 jit是不知道任何c#的條條框框的。

本質上來說,上面的例子和這個沒有區別:

code

public

class

cprivate

static

void

reallydoit(

string

s)private

static

void

reallydoit(

object

t)當編譯器為呼叫reallydoit生成(il)的時候, 它會挑選object作為引數的版本,因為那是它最好的選擇。如果有人用string來呼叫方法,那麼它還是會選擇object作為引數的版本。

現在,如果你確實想根據引數的型別在執行時做過載決議,我們能為你做到。那就是c# 4.0的新特性dynamic能做的。只要把object替換成dynamic, 那麼當你呼叫那個object的方法時, 我們會在執行時根據它所知道的所有的執行時型別,執行過載決議並且動態地生成編譯器選擇的呼叫**。

模板 泛型程式設計

我們從乙個很簡單的問題來進入泛型程式設計 question 如何寫乙個通用的加法函式 使用函式過載。針對每乙個所需相同行為的不同型別重新實現 函式過載的缺點 1 只要有 型別出現,就要重新新增對應函式 2 除型別外,所有函式的函式體都相同,的復用率不高 3 如果函式知識返回值型別不同,函式過載不能解...

泛型程式設計 模板

泛型程式設計 重點 1.熟悉模板的語法 2.模板的原理 3.理解 基礎語法 類和物件 模板 去解決c語言不足的問題和意義 使用模板,編寫跟型別無關的 例如在一些函式和類的時候,針對不同型別需要寫很多重複的 swap函式 類 比如我們想實現乙個資料結構棧stack,stack的多個物件,st1存int...

C 模板(泛型)

模板概念 模板是建立通用模具,大大提高復用性,將型別引數化。c 泛式程式設計思想,主要利用的技術就是模板 c 提供模板機制 函式模板和類模板 函式模板和類模板區別 類模板沒有自動型別推導使用方式 類模板在模板引數列表中可以有預設引數 作用 建立通用函式,其函式返回值型別和形參型別可以不具體制定,用乙...