2011-04-19 138 views
6

在Java中,Class有通用參數X.但是C#的Type類沒有這個方法。什麼是Java的類<X>類型的C#等價物?

所以在C#中,一個人如何做到下面的Java代碼相當於?:

public <X> X methodThatReturns(Class<X> clazz) { ... } 

似乎有沒有在C#的方式連接有返回值,並傳遞類型。

澄清
幾個答案都表明該方法的參數是沒有必要的,因爲該方法可以簡單地定義爲methodThatReturns<X>()

但是,如果你做一些未知類型的變量,t,也基本上沒有辦法把這樣一個通用的方法,這樣它會返回t類型的對象?

在Java中,您可以自由地傳遞Class<X>變量而不會丟失類型信息,但似乎在C#中如果傳遞等效的Type變量,則可能會遇到限制,因爲您無法使用它們當你需要調用泛型方法時。

+0

http://msdn.microsoft.com/en-us/library/ms379564(v=vs.80).aspx – asawyer 2011-04-19 20:34:57

+2

我不是一個C#程序員,但我認爲這個習語很少見在C#中,因爲C#沒有類型擦除。通用類型信息在運行時保留,不會丟失。 – 2011-04-19 20:35:45

+0

不要以爲有一個。 – clamchoda 2011-04-19 20:35:49

回答

9
public X methodThatReturns<X>(Class<X> clazz) { ... } 

而且記住,在C#中不存在類型擦除所以你可以做這樣的事情typeof(T)沒有案例類的擔憂,就是要java的「類」的對象,而不是「一些類」佔位符:

public X methodThatReturns<X>(X value) 
{ 
    Type x = typeof(X); // that's fine 
    if (value is SomeType) { } // that's fine too  
    return (X)someObject; // I think you get the point 
} 

編輯:

同樣,由於泛型類型信息不編譯後失去了你並不需要在類型傳遞明確:

public X methodThatReturns<X>() 
{ 
    Type xType = typeof(X); // Type is to C#/.Net what Class<X> is to Java. 
} 
+0

感謝Ivan,但我正在尋找一種方法,將X的「類型」作爲參數,而不是X的實例...類似於類型。 – slattery 2011-04-19 20:55:58

+0

沒有辦法把它作爲一個參數,但在C#中,你不需要,你可以做到這一點的方法中,即使它沒有一個參數:'輸入x = typeof運算(X)'。 Type是C#中Class的等價物。 – 2011-04-19 21:09:09

+0

這很不幸。無法通過傳入類型表達動態返回類型,並且在某些情況下,獲取編譯器類型檢查非常有限。 – andyczerwonka 2016-11-23 23:27:13

3

在C#這將是

public X methodThatReturns<X>() { ... } 

,您可以使用typeof(X),而不是使用參數clazz

1

我不是Java泛型100%達得到對X型...你是否試圖聲明一個返回相同類型的方法?

public T MethodThatReturns<T>(T input) { ... } 

此方法在任何類型上都是泛型的,並返回它傳遞的相同類型。您可以通過調用這個:

AnyTypeAtAll foo = new AnyTypeAtAll(); 
AnyTypeAtAll bar = MethodThatReturns(foo); 

注意這裏在調用MethodThatReturns沒有<AnyTypeAtAll>,編譯器可以計算出來給你傳遞的參數。但是,請注意,編譯器是這樣做的,而不是運行時,所以它只會使用foo類型的變量,而不是foo指向的對象類型。


在另一方面,如果這是Java語法不帶任何「真正」的參數,那麼一個簡單的方法:

public T MethodThatReturns<T>() 
{ 
    Type clazz = typeof(T); 
    .... 
} 

在這個方法中,你可以把T中的一樣,你會任何其他類,它將特指該方法被調用的類型,而不是object或類似的東西。你可以把它放到where T : class,使該方法比較空(它阻止你使用int作爲通用型),或where T : new()限制泛型類型有一個默認的構造函數,所以你可以做T foo = new T();

0

我熟悉Java和.NET泛型,我在我的Java項目中使用了很多像這樣的構造。我最喜歡的用途之一是應對非Java的泛型集合這是從Hibernate等外部的代碼返回(我認爲Hibernate的最新版本可能支持泛型,但我不能肯定這一點。我們正在使用相當因爲舊版本的它是有太多的代碼,就必須更新,如果我們永遠改變了它一個長期運行的項目)的功能是這樣的:。

public <X> List<X> TypedList(List<?> lst, Class<X> cls) { 
    return (List<X>) lst; 
} 

這一切都非常簡單,最重要的事情是我沒有創建一個虛擬對象傳遞給函數,我只是把它作爲:

List<MyObject> myLst = TypedList(lst, MyObject.class); 

需要注意的另一個重要的事情是cls參數完全不用。這只是給人一種具體類型爲X.

你做同樣的事情在C#中有一點點不同的方式表示。你可能會認爲同樣的功能會是這個樣子:

public List<X> TypedList<X>(IList lst) 
{ 
    return (List<X>) lst; 
} 

但是,你就死定了錯誤的。

的問題是,Java使用一種稱爲類型擦除招,這基本上意味着,當代碼實際上是編譯,所有的通用參數從代碼中刪除。所以在Java虛擬機的世界裏,有沒有這樣的事,作爲一個List<X>或任何其他仿製藥,它們都是簡單的List和其他非泛型類型。這意味着泛型僅用於幫助您編碼,並且不會在運行時強制執行。

但是,在C#中沒有類型擦除和泛型在運行時強制執行。這意味着,與上述功能時使用以下將產生一個運行時異常:

List<object> lstObj = TypedList<object>(new List<string>()); 

其原因是,List<string>List<object>被認爲是兩個完全不同的類。如果沒有編譯器錯誤,你甚至不能執行List<object> lstObj = (List<object>) new List<string>();這意味着函數不能返回傳遞給它的同一個對象。我們必須創建正確類型的新對象,並返回一個。最基本的形式如下:

public List<X> TypedList<X>(IList lst) 
{ 
    List<X> lstOut = new List<X>(); 
    for (int i = 0; i < lst.Count; i++) 
    { 
     if (lst[i] is X) lstOut.Add((X) lst[i]); 
    } 
    return lstOut; 
} 

這是相當無聊和樣板代碼,但它的工作原理。對於更短更乾淨的東西,LINQ在這裏是爲了節省一天的時間。看看下面的:

public List<X> TypedList<X>(IList lst) 
{ 
    return lst.OfType<X>().ToList(); 
} 

OfType<X>()抓住LST中屬於X型(或後代)的所有項目,並跳過任何都沒有。 ToList()然後建立一個新的List<X>包含從OfType<X>()傳遞給它的所有成員。這種方法的另一個優點是,我們實際上可以善堂參數從一種IListIEnumberable,這是所有的集合類型實現的改變。

另一件需要指出的事情是,它不做類型轉換,只進行類型檢查。所以這意味着如果你想採取List<long>並將其轉換爲List<int>List<string>,那麼你需要做其他事情。隨着LINQ,這仍然會是很簡單的:

List<long> lstLng = new List<long>(); 
lstLng.Add(1); 
List<int> lstInt = lstLng.Cast<int>().ToList(); 
List<string> lstStr = lstLng.Select(lng => lng.ToString()).ToList(); 

[注:如果你不熟悉的lng => lng.ToString()部分,它被稱爲Lambda表達式]

Cast<int>(),不像OfType<int>(),實際上會嘗試將每個項目轉換爲一個int,跳過所有無法轉換的項目。 Select()只是讓你從現有的集合中構建一個全新的集合,使用幾乎任何你想要的代碼。

我希望我的真實世界的例子有助於人們更好地理解.NET和Java在使用泛型類型函數時的差異。

+0

有趣的閱讀。我很高興你發現這些LINQ方法對你當前的情況很有幫助。不過,我認爲他們身後並沒有什麼特別的東西。我實際上創建了自己的OfType 擴展方法,然後才意識到已經有內置的方法。從列表到列表的限制可能更多地與類型差異有關。我仍然使用C#3.5,但我認爲4.0引入了對此的更多支持(例如協變和逆變的'in'和'out'關鍵字)。 – slattery 2012-12-16 02:15:29

+0

@slattery實際上,方差不適用於類,只適用於接口和代表。List確實實現了IEnumerable,它是協變的,所以你可以做一些像'IEnumerable enumObj = new List ();'但是你仍然不能去'列表 lstObj =(列表)enumObj;'沒有拋出異常,因爲具體類型總是列表。因此,當您執行類似'List lstObj = lstStr.OfType ().ToList();'創建並分配一個全新的List對象。 – CptRobby 2013-01-10 23:51:12

+0

@slattery查閱這篇文章以獲取更多有關方差的信息:http://msdn.microsoft.com/en-us/library/dd799517.aspx。有趣的是,IEnumberable 是變體,而ICollection 不是。我認爲這是因爲ICollection 中定義的一些方法將T作爲參數。 (反變化仍然與我的心靈混淆......大聲笑)感謝您的意見。 ;-) – CptRobby 2013-01-11 00:06:30

相關問題