简体   繁体   English

在C#泛型中,Java通配符的等价物是什么

[英]What is the equivalent of Java wildcards in C# generics

I'm developing an application where I the need to invoke a method of a generic class and I don't care about the instances actual type. 我正在开发一个应用程序,我需要调用泛型类的方法,而不关心实例的实际类型。 Something like the following Java code: 像下面的Java代码:

public class Item<T>{
  private T item;

  public doSomething(){...}
}

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

At the time I was on a hurry, so I solved my problem by defining a interface with the methods I needed to invoke and made the generic class implement it. 当时我很着急,所以我通过使用我需要调用的方法定义一个接口并使泛型类实现它来解决我的问题。

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();
}

This workaround works fine, but I'd like to know what is the correct way to achieve the same behavior. 这种解决方法工作正常,但我想知道实现相同行为的正确方法是什么。

EDIT: 编辑:

I forgot to refer that the caller of processItems doesn't know the actual types. 我忘了提到processItems的调用者不知道实际的类型。 Actually the idea was that the array passed as argument to processItems could contain intermixed types. 实际上,这个想法是作为参数传递给processItems的数组可能包含混合类型。 Since its not possible to have such an array in .Net, using a non generic base class or interface seems to be the only way. 由于在.Net中不可能有这样的数组,因此使用非泛型基类或接口似乎是唯一的方法。

The normal way to do this would be to make the method generic: 执行此操作的常规方法是使方法通用:

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

Assuming the caller knows the type, type inference should mean that they don't have to explicitly specify it. 假设调用者知道类型,类型推断应该意味着他们不必明确指定它。 For example: 例如:

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

Having said that, creating a non-generic interface specifying the type-agnostic operations can be useful as well. 话虽如此,创建一个指定类型不可知操作的非泛型接口也很有用。 It will very much depend on your exact use case. 这在很大程度上取决于您的确切用例。

I see that you only want to invoke some method with no parameters... there's already a contract for that: Action . 我看到你只想调用一些没有参数的方法......已经有了一个合同: Action

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

Client: 客户:

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);

There's no way you can omit Type Parameters in .NET generic implementation; 在.NET泛型实现中,你无法省略Type Parameters; this is by design. 这是设计的。 In fact, this can only be achieved in Java because of its type-erasure-based implementation. 实际上,由于其基于类型擦除的实现,这只能在Java中实现。

You can only use a base non-generic interface (think IEnumerable<T> and IEnumerable ). 您只能使用基本的非泛型接口(想想IEnumerable<T>IEnumerable )。

I've been struggling with the same issue when it came to porting stuff from Java where I've had constructs like 当我从Java那里移植东西时,我一直在努力解决同样的问题

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

Fortunately it turns out that a generic ICollection is also a non-generic ICollection and if someone needs to treat the elements in it as pure objects it is still possible: 幸运的是,通用的ICollection也是一个非通用的ICollection,如果有人需要将其中的元素视为纯对象,它仍然是可能的:

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

That way, since we don't care about the actual type of elements in collection all we get here are objects. 这样,因为我们不关心集合中元素的实际类型,所以我们在这里得到的是对象。 A note here: if the collection was holding primitive types (int or byte for example) then autoboxing kicks in which might introduce performance penalty. 这里有一个注释:如果集合中包含原始类型(例如int或byte),那么自动装箱可能会引发性能损失。

Further to Jon's post. 继乔恩的帖子之后。 making the method generic (a template) negates the requirement for this sort of functionality (using <?>). 使方法通用(模板)否定了对这种功能的要求(使用<?>)。 You can always feed a type into a generic class/function and for cases where you don't know what type you will need you can make the offending method/class generic as well... ultimately the user has to provide a type when calling such a function or using a generic class, for the code to be able to compile... otherwise you will get some compiler errors. 你总是可以将一个类型提供给一个通用的类/函数,如果你不知道你需要什么类型,你可以使有问题的方法/类通用...最终用户在调用时必须提供一个类型这样的函数或使用泛型类,代码能够编译...否则你会得到一些编译器错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM