我正在开发一个应用程序,我需要调用泛型类的方法,而不关心实例的实际类型。类似于以下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中不可能有这样的数组,因此使用非泛型基类或接口似乎是唯一的方法。
答案 0 :(得分: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);
话虽如此,创建一个指定类型不可知操作的非泛型接口也很有用。这在很大程度上取决于您的确切用例。
答案 1 :(得分: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);
答案 2 :(得分:1)
在.NET通用实现中,你无法省略类型参数;这是设计的。实际上,这只能通过Java实现,因为它基于类型擦除的实现。
您只能使用基础非通用界面(请考虑IEnumerable<T>
和IEnumerable
)。
答案 3 :(得分:0)
继乔恩的帖子之后。使方法通用(模板)否定了对这种功能的要求(使用&lt;?&gt;)。你总是可以将一个类型提供给一个通用的类/函数,如果你不知道你需要什么类型,你可以使有问题的方法/类通用...最终用户在调用时必须提供一个类型这样的函数或使用泛型类,代码能够编译...否则你会得到一些编译器错误。
答案 4 :(得分:0)
当我从Java那里移植东西时,我一直在努力解决同样的问题
if (o instanceof Collection<?>) doSoemthing((Collection<?>)o);
幸运的是,通用的ICollection也是一种非通用的ICollection,如果有人需要将其中的元素视为纯对象,那么它仍然是可能的:
if (o is ICollection) DoSomething((ICollection)o);
这样,既然我们不关心集合中元素的实际类型,我们在这里得到的就是对象。 这里有一个注释:如果集合中包含原始类型(例如int或byte),那么自动装箱可能会引发性能损失。