简体   繁体   English

C# 等效于 Java 列表<? extends Class>

[英]C # equivalent of Java List<? extends Class>

I have a basic structure of generic's classes我有一个泛型类的基本结构

public class Parent<T> where T : Parent<T>
{
   Action<T> Notify;
}

public class Child : Parent<Child>
{
}

And I want to have a list so that Child objects can be put there我想要一个列表,以便可以将 Child 对象放在那里

List<Parent> parents = new List<Parent>();

In java I just can write List<? extends Parent>在 Java 中,我只能写List<? extends Parent> List<? extends Parent> and all Parent's subclasses easily can be added to the list. List<? extends Parent>和所有 Parent 的子类都可以轻松添加到列表中。 Is there any alternative of this in C#?在 C# 中是否有其他选择?

You can't do the same thing as Java, because in Java, generics use type erasure and break variance.您不能做与 Java 相同的事情,因为在 Java 中,泛型使用类型擦除和中断差异。 Essentially, your Java code turns everything into List<object> , and hopes for the best.本质上,您的 Java 代码将所有内容都转换为List<object> ,并希望做到最好。 The only reason why List<?> is better than List<Object> is that not everything is an Object in Java - in C#, you can put an integer inside a List<object> just fine. List<?>优于List<Object>的唯一原因是在 Java 中并非所有东西都是Object - 在 C# 中,您可以在List<object>放入一个整数就好了。 Mind, a List<int> will perform much better than List<object> , if you can afford it - that's one of the big reasons why generics were originally added to C#.请注意,如果您负担得起, List<int>性能将比List<object>好得多 - 这是泛型最初添加到 C# 的重要原因之一。

C# is a bit stricter than that. C# 比这更严格一些。 You can't do anything like new List<Parent<T>>() that would allow any kind of Parent<T> .你不能做任何像new List<Parent<T>>()这样会允许任何类型的Parent<T>事情。 If you had more limited requirements, you could use a variant interface instead, but that wouldn't work with List<T> for obvious reasons.如果您有更有限的要求,您可以改用变体接口,但由于显而易见的原因,这不适用于List<T>

Your only real option is to make the base class non-generic.您唯一真正的选择是使基类成为非泛型。 The user of your list can't know anything about the T in advance anyway, so any part of the Parent interface that returns or takes T wouldn't be useful without casting anyway (Java does the casting for you, but it's still casting - neither Java's nor C#'s generics are powerful enough for what you're trying to do).无论如何,您的列表中的用户无法提前了解T任何信息,因此返回或接受TParent接口的任何部分如果不进行任何转换都将毫无用处(Java 为您进行了转换,但它仍在转换 - Java 和 C# 的泛型都不够强大,无法满足您的需求)。

public abstract class Parent
{
  // The common methods
  public abstract int Id { get; }
}

public abstract class Parent<TChild> : Parent, IEnumerable<TChild>
{
  // The methods that are TChild-specific - if you don't need any of those, just drop
  // this class, the non-generic one will work fine
  private List<TChild> children;
  public void Add(TChild child) => ...
  public TChild this[int index] => ...
}

public class Child : Parent<TChild>
{
  ...
}

Now to get a list of all possible children, you can use现在要获取所有可能的孩子的列表,您可以使用

var list = new List<Parent>();

And when you need to get eg all the Child items, you can do当您需要获取例如所有Child项时,您可以这样做

var children = list.OfType<Child>();

Just for completeness sake, you can get similar behavior to Java's with C#'s dynamic .为了完整起见,您可以使用 C# 的dynamic获得与 Java 类似的行为。 But I'm not even going to show any sample of that - dynamic is a useful tool, but mainly for more dynamic typing problems.但我什至不打算展示任何示例 - dynamic是一个有用的工具,但主要用于更动态的类型问题。 It's overkill for something as simple as this, and trades compile-time issues for run-time issues.对于像这样简单的事情来说这是矫枉过正的,并且将编译时问题换成了运行时问题。

In general, if you ever use Parent<T> directly, it should be in a generic method - eg an extension method that has some common functionality for all Parent<T> s.一般来说,如果你曾经直接使用Parent<T> ,它应该是一个泛型方法——例如一个扩展方法,它具有所有Parent<T>的一些通用功能。 You can't instantiate a generic type that doesn't have all the type arguments known at the time in C#.您不能实例化一个不具有当时在 C# 中已知的所有类型参数的泛型类型。

Declaration List<Parent> parent;声明List<Parent> parent; does not compile, since it requires type argument.不编译,因为它需要类型参数。

And when you say, public class Child : Parent<Child> it inherits Parent<Child> and not Parent<T>当你说, public class Child : Parent<Child>它继承Parent<Child>而不是Parent<T>

So List<Parent<Child>> list;所以List<Parent<Child>> list; will only accept objects of Child class, and not of any other subclass of Parent.将只接受 Child 类的对象,而不接受 Parent 的任何其他子类。

Still you can achieve what you need with help of an interface as below: working fiddle here您仍然可以在如下界面的帮助下实现您需要的功能:在这里工作小提琴

public class Program
{
    public static void Main()
    {
        List<Parent<IParent>> parentList = new List<Parent<IParent>>();

        parentList.Add(new Child1());
        parentList.Add(new Child2());       
    }
}
public class Parent<T> 
{ }
public interface IParent
{ }

public class Child1 : Parent<IParent>, IParent
{ }

public class Child2 : Parent<IParent>, IParent
{ }

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

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