2011-07-01 97 views
7

C++模板的好處之一是您(隱式地)可以要求某種類型的簽名(例如,類型T需要有一個不帶參數並返回int的函數x)。 C#泛型支持類似的東西嗎?C#泛型是否支持類型簽名約束?

我知道基於基類或接口的約束,但這不是我正在尋找的。

(作爲一個C++程序員學習C#我可能是錯誤的,這是你想在C#中的功能。在這個任何評論都將和appriciated ...)

+4

但是,接口約束已經是表達'T實現方法X()匹配某個簽名'的好方法,你不覺得嗎? –

回答

6

除了您已經看到的約束條件(公平地說,涵蓋了許多常見的情況)之外,沒有什麼。還有一些常用的解決方法:

  • dynamic,在4.0
  • 手冊鴨打字使用反射或IL代等

這些都沒有靜態類型檢查等,雖然。

+0

動態可能是我能得到的最接近的。事實上,我經常把C++模板看作是一種「動態編譯時語言」(這可能是除了我以外的任何人都沒有意義的短語) –

+0

@Tobias我會用「static-checked duck-鍵入「; p('dynamic'具有運行時間的含義,但我知道你的意思) –

+0

,突然它對每個人都有意義:) –

0

有5種類型的約束你可以在.Net中使用泛型:

  1. 派生約束表明類型參數的優勢。
  2. 接口約束是由類型參數實現的接口。
  3. 值類型約束將類型參數限制爲值類型。
  4. 引用類型約束將類型參數限制爲引用類型。
  5. 構造函數約束規定type參數具有默認或無參數構造函數。

This頁面顯示更多信息。

+0

「我知道基於基類或接口的約束,但這不是我正在尋找的。」 –

4

是的,通過一個接口。您可以定義一個具有必須實現特定接口的類型的通用對象。在該接口中,您基本上會強制將任何添加到該通用列表的對象強制爲具有特定的簽名。

不管你是不是不是尋找,那就是你如何實現它。 :)

+1

儘管如此,這仍然不能涵蓋所有選項 - 帶參數,運算符,靜態方法的構造函數,等等...... –

+0

@Marc在這種情況下,沒有一個完美的解決方案 - 就像你在答案中提到的一樣。 OP將不得不稍微彎腰才能完成他的任務。他可能不需要你提到的任何東西。他希望他的泛型類符合「不帶參數的函數x並返回一個int」 –

+0

@Marc,我同意,並支持非默認構造函數的約束將是很好的恕我直言。其他人,不是那麼多,尤其是*運營商:) –

1

不,這是interface的用途。創建一個interface,用於定義要在類型約束中實施的合同。然後在約束中指定。

0

不,在c#中不支持。就像你說的,最接近的事情要求你讓這些類實現一個通用接口。

可能嘗試通過簽名來查找方法來模擬反射行爲,但這是運行時約束,而不是編譯時約束。

0

不,C#沒有這樣的限制。如你所知,通用約束只能強制繼承基類或接口,或一些其他約束(構造函數約束new(),引用類型約束class,值類型約束struct)。

您可能可以使用代表實現您想要的行爲,並且有許多可用的通用代表。
例如,Func<int>是不帶參數並返回int的代表。 Func<string, DateTime, int>需要stringDateTime並返回int等...

3

不,這是不可能的。它主要是由C++模板和C#泛型之間的差異造成的:

當您編譯C++模板時,生成的代碼的類型如vector<int>vector<string>。這意味着編譯器必須知道所有可能的類型參數,但這也意味着它可以檢查它們的正確性。

當您編譯C#泛型類型時,實際上只是創建一個泛型類型:List<T>。因此,C#編譯器不必知道編譯類型中的所有可能類型,這意味着您可以在二進制庫中使用泛型類型,這對於C++來說是不可能的。但是這也意味着你不能檢查所有的類型。爲了能夠做到這一點,存在約束,但是它們不能做C++編譯時檢查可以做的幾件事情,比如檢查某些方法的存在(不使用接口或某些基類)或存在合適的運算符。

在C#4,你可以達到的效果有點類似這種使用dynamic模板,但這並沒有編譯時檢查,這意味着你失去了安全性 - 你可以把不有型合適的成員,直到您在運行時到達該行代碼時纔會發現。