2011-04-19 63 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

相关问题