8

I have a collection class like this:

public class SomeDataCollection : List<ISomeData>
{
    // some method ...
}

but I can't do this:

SomeDataCollection someDatas = new List<ISomeData>();

Cannot implicitly convert type List<ISomeData> to SomeDataCollection. An explicit conversion exists (are you missing a cast?)

so I try to create an implicit coverter inside SomeDataCollection collection class:

public static implicit operator SomeDataCollection(List<ISomeData> l)
{
    var someDatas = new SomeDataCollection();
    someDatas.AddRange(l);
    return someDatas;
}

but it said that I can't create such converter:

SomeDataCollection.implicit operator SomeDataCollection(List<ISomeData>): user-defined conversions to or from a base class are not allowed

And when I cast it like this:

SomeDataCollection someDatas = (SomeDataCollection)new List<ISomeData>();

it throws an error that said:

System.InvalidCastException: Unable to cast object of type List<ISomeData> to type SomeDataCollection.

How can I do this:

SomeDataCollection someDatas = new List<ISomeData>();

without getting an error? Please help. Thanks in advance.

John Isaiah Carmona
  • 5,260
  • 10
  • 45
  • 79
  • possible dupplicate: http://stackoverflow.com/questions/3401084/user-defined-conversion-operator-from-base-class – albertjan Jun 27 '12 at 07:47

4 Answers4

6

A new List<ISomeData>(); is still just a List<ISomeData>. It isn't a SomeDataCollection. The point of subclassing is that the subclass could have extra state etc, but an object (once created) never changes type.

You are not allowed to create operators between types in the same hierarchy, as that would subvert the usual and expected casting behaviour.

You could use simply:

var data = new SomeDataCollection();

However I should add that frankly it is rarely useful to subclass List<T>. Not least, it doesn't expose any useful virtual methods, so you can't tweak the behaviour. I would honestly just use a List<ISomeData> (and remove SomeDataCollection completely) unless I have a clear and demonstrable purpose for it. And then: I might either encapsulate the list, or inherit from Collection<T>.

You could always just add the method as an extension method?

public static class Utils {
    public static void SomeMethod(this IList<ISomeData> list) {
      ...
    }
}

then:

var list = new List<ISomeData>();
...
list.SomeMethod();
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • I do not actually just put a freshly instantiated `List` in `SomeDataCollection`, that was just a sample :P. I use`List` because it already has some function for adding, removing, etc objects, and I have some additional methods and properties in my `SomeDataCollection` class whcih is specific only to type `List`. – John Isaiah Carmona Jun 27 '12 at 07:53
  • 1
    @John IMO having something both be a list *and* have its own state is a mistake; many frameworks/libraries *hate* that - binding, serialization, materialization, etc. IMO you should have an object which *has* those properties, and which also *has* an `IList Items {get;}` – Marc Gravell Jun 27 '12 at 08:16
  • It is often useful to subclass List. A good example might be a list that can adapt to different conditions and has properties and methods added for that purpose. However, even in those cases, T usually remains T. – Thomas Phaneuf Aug 30 '20 at 19:58
  • @ThomasPhaneuf since `List` doesn't expose any polymorphic APIs, it is unclear what it could usefully do to "adapt" to anything – Marc Gravell Sep 01 '20 at 09:49
2

First of all, why do you want to write new List<ISomeData> into a variable defined as SomeDataCollection? It is possible that you actually wanted to SomeDataCollection someDatas = new SomeDataCollection();

As for error messages, the first error message tells you that List<ISomeData> is not derived from SomeDataCollection, therefore you can't do with it something you would do with SomeDataCollection, therefore you can't write it to the variable which is defined as SomeDataCollection (imagine e.g. if SomeDataCollection had public void someMethod() in it, and later in the code you'd call someDatas.someMethod()).

The second error message tells you that converters are intended for converting between completely different types, not between the based and derived type. Otherwise, what would you expect to get e.g. in the following example:

SomeDataCollection a = new SomeDataCollection();
List<ISomeData> b = (List<ISomeData>)a;
SomeDataCollection c = (SomeDataCollection)b;

Should it call your converter or not?

Basically code you're trying to write is very wrong to begin for, so we need to know what're you trying to do, and then maybe well'be able to tell you the solution of your root problem (and not of the problem "how to make this code compile").

penartur
  • 9,792
  • 5
  • 39
  • 50
2

Isn't it better to implement a constructor in SomeDataCollection?

public SomeDataCollection() : base() { }

This could of course be complemented with

public SomeDataCollection(IEnumerable<ISomeData> collection) 
    : base(collection) { }

Then you should be able to initialize your SomeDataCollection like this instead:

SomeDataCollection someData = new SomeDataCollection();
SomeDataCollection someOtherData = 
    new SomeDataCollection(collectionOfSomeData);

and still have access to all the public methods and properties in List<ISomeData>.

Anders Gustafsson
  • 15,837
  • 8
  • 56
  • 114
0

It does not problem with generics. In C# you are not allowed to explicitely convert a base class into a derived class.

Eugene
  • 2,858
  • 1
  • 26
  • 25