【问题标题】:What is the equivalent of Java wildcards in C# genericsC#泛型中Java通配符的等价物是什么
【发布时间】:2010-10-06 09:06:54
【问题描述】:

我正在开发一个应用程序,我需要调用一个泛型类的方法,而我并不关心实例的实际类型。类似于以下 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 中不可能有这样的数组,因此使用非泛型基类或接口似乎是唯一的方法。

【问题讨论】:

    标签: c# generics wildcard


    【解决方案1】:

    在从 Java 移植东西时,我一直在努力解决同样的问题,因为我有类似的结构

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

    幸运的是,泛型 ICollection 也是非泛型 ICollection,如果有人需要将其中的元素视为纯对象,它仍然是可能的:

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

    那样,因为我们不关心集合中元素的实际类型,所以我们在这里得到的只是对象。 此处需要注意:如果集合包含原始类型(例如 int 或 byte),则自动装箱会启动,这可能会导致性能损失。

    【讨论】:

      【解决方案2】:

      我看到你只想调用一些不带参数的方法......已经有一个合同: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);
      

      【讨论】:

        【解决方案3】:

        关于 Jon 的帖子。使方法通用(模板)否定了对这种功能的要求(使用 >)。您始终可以将类型提供给泛型类/函数,并且对于您不知道需要什么类型的情况,您也可以将有问题的方法/类设为泛型......最终用户必须在调用时提供类型这样的函数或使用泛型类,以便代码能够编译......否则你会得到一些编译器错误。

        【讨论】:

          【解决方案4】:

          执行此操作的正常方法是使方法通用:

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

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

          【讨论】:

          • 布拉格,太快了几秒钟。 :P
          • 是的,也打败了我。不过,您可以使用调用者的示例进行编辑吗?
          • 乔恩,你在这里写java吗?
          【解决方案5】:

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

          您只能使用基本的非通用接口(想想IEnumerable&lt;T&gt;IEnumerable)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-12-07
            • 2010-11-22
            • 1970-01-01
            • 2011-10-13
            相关资源
            最近更新 更多