2009-02-09 73 views
20

我正在开发一个应用程序,我需要调用泛型类的方法,而且我不关心实例的实际类型。类似下面的Java代码:什么是C#泛型中的Java通配符相当于

public class Item<T>{ 
    private T item; 

    public doSomething(){...} 
} 

... 
public void processItems(Item<?>[] items){ 
for(Item<?> item : items) 
    item.doSomething(); 
} 

当时我是在赶时间,所以我定义与我需要调用的方法的接口,解决了我的问题,并提出了通用类实现它。

public interface IItem 
{ 
    void doSomething(); 
} 

public class Item<T> : IItem { 
    private T item; 

    public void doSomething(){...} 
} 

... 
public void processItems(IItem[] items) 
{ 
foreach(IItem item in items) 
    item.doSomething(); 
} 

此变通办法正常工作,但我想知道什么是要实现相同的行为的正确方法。

编辑:

我忘了提及的是的processItems调用者不知道实际的类型。实际上这个想法是,作为参数传递给processItems的数组可能包含混合类型。由于在.Net中不可能有这样的数组,因此使用非泛型基类或接口似乎是唯一的方法。

回答

25

正常的方式做,这将是使该方法一般:

public void ProcessItems<T>(Item<T>[] items) { 
    foreach(Item<T> item in items) 
    item.DoSomething(); 
} 

假设呼叫者知道的类型,类型推断应该意味着他们没有显式指定它。例如:

Item<int> items = new Item<int>(); // And then populate... 
processor.ProcessItems(items); 

尽管如此,创建一个指定类型无关操作的非通用接口也是有用的。这将非常依赖于你的确切用例。

+0

Blargh,几秒钟过早。 :P – 2009-02-09 11:25:53

1

您无法在.NET通用实现中省略类型参数;这是设计。事实上,这只能在Java中实现,因为它基于类型擦除的实现。

您只能使用基本非通用接口(请考虑IEnumerable<T>IEnumerable)。

0

继续Jon的文章。使方法通用(模板)否定这种功能的要求(使用<?>)。你总是可以将一个类型提供给一个通用的类/函数,并且在你不知道你需要什么类型的情况下,你也可以制作违规方法/类的通用类型......最终用户在调用时必须提供一个类型这样的函数或使用泛型类的代码,以便能够编译...否则您将得到一些编译器错误。

3

我看到你只想调用一些没有参数的方法......已经有一个合约:Action

public void processItems(IEnumerable<Action> actions) 
{ 
    foreach(Action t in actions) 
    t(); 
} 

客户:

List<Animal> zoo = GetZoo(); 
List<Action> thingsToDo = new List<Action>(); 
// 
thingsToDo.AddRange(zoo 
    .OfType<Elephant>() 
    .Select<Elephant, Action>(e => e.Trumpet)); 
thingsToDo.AddRange(zoo 
    .OfType<Lion>() 
    .Select<Lion, Action>(l => l.Roar)); 
thingsToDo.AddRange(zoo 
    .OfType<Monkey>() 
    .Select<Monkey, Action>(m => m.ThrowPoo)); 
// 
processItems(thingsToDo); 
0

我一直在挣扎了同样的问题,当它来到从Java移植的东西在那里我已经构造,如

if (o instanceof Collection<?>) doSoemthing((Collection<?>)o); 

好在事实证明一个通用的ICollection也是一个非泛型的ICollection,如果有人需要将其中的元素作为纯对象处理,它仍然是可能的:

if (o is ICollection) DoSomething((ICollection)o); 

这样,因为我们不关心集合中元素的实际类型,所以我们在这里得到的是对象。 这里有一个注释:如果集合保存了原始类型(例如int或者byte),那么可能会引入性能损失的自动装配踢。