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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/527766/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 06:51:01  来源:igfitidea点击:

What is the equivalent of Java wildcards in C# generics

c#genericswildcard

提问by jassuncao

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 processItemsdoesn't know the actual types. Actually the idea was that the array passed as argument to processItemscould contain intermixed types. 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.

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

采纳答案by Jon Skeet

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 callerknows 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.

话虽如此,创建一个指定类型不可知操作的非通用接口也很有用。这在很大程度上取决于您的确切用例。

回答by Anton Gogolev

There's no way you can omit Type Parameters in .NET generic implementation; this is by design. In fact, this can only be achieved in Java because of its type-erasure-based implementation.

在 .NET 泛型实现中你不能省略类型参数;这是设计使然。事实上,这只能在 Java 中实现,因为它是基于类型擦除的实现。

You can only use a base non-generic interface (think IEnumerable<T>and IEnumerable).

您只能使用基本的非通用接口(thinkIEnumerable<T>IEnumerable)。

回答by jheriko

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.

继乔恩的帖子之后。使方法通用(模板)否定了对此类功能的需求(使用 <?>)。您始终可以将类型输入到泛型类/函数中,对于不知道需要什么类型的情况,您也可以使违规方法/类泛型......最终用户必须在调用时提供类型这样的函数或使用泛型类,使代码能够编译...否则你会得到一些编译器错误。

回答by Amy B

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

回答by Matthias Hryniszak

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),那么自动装箱可能会引入性能损失。