C # equivalent of Java List<? extends Class>

|▌冷眼眸甩不掉的悲伤 提交于 2021-02-05 06:28:45

问题


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

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

In java I just can write List<? extends Parent> and all Parent's subclasses easily can be added to the list. Is there any alternative of this in C#?


回答1:


You can't do the same thing as Java, because in Java, generics use type erasure and break variance. Essentially, your Java code turns everything into List<object>, and hopes for the best. 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. 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#.

C# is a bit stricter than that. You can't do anything like new List<Parent<T>>() that would allow any kind of 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.

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

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 e.g. all the Child items, you can do

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

Just for completeness sake, you can get similar behavior to Java's with C#'s dynamic. But I'm not even going to show any sample of that - dynamic is a useful tool, but mainly for more dynamic typing problems. 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 - e.g. an extension method that has some common functionality for all Parent<T>s. You can't instantiate a generic type that doesn't have all the type arguments known at the time in C#.




回答2:


Declaration 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>

So List<Parent<Child>> list; will only accept objects of Child class, and not of any other subclass of 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
{ }


来源:https://stackoverflow.com/questions/60333112/c-equivalent-of-java-list-extends-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!