Maris
Maris

Reputation: 4776

Issue with casting List<ClassA> where ClassA:Generic<Int32> to List<Generic<Int32>>

I have the next classes:

public class EntityBase<T>
{
    public T Id { get; set; }

}

And it's implementers:

public class ClassA : EntityBase<Int32>
{
     ...
}

public class ClassB : EntityBase<Int64>
{
     ...
}

And in the code, which dont know about classes - ClassA and ClassB it knows only about existance of the EntityBase<...>, I do something like this:

     // Here for sure I get the list of `ClassA`
     object obj = GetSomeHowListOfClassA();
     List<EntityBase<Int32>> listOfEntityBases = (List<EntityBase<Int32>>)obj;

And I get the error:

Unable to cast object of type 'System.Collections.Generic.List`1[...ClassA]' to type 'System.Collections.Generic.List`1[...EntityBase`1[System.Int32]]'.

I fix it like this:

var listOfEntityBases = new List<EntityBase<Int32>>(obj);

But I dont like this way, because I'm creating new List<>. Is there way to cast it? Thx for any advance.

Upvotes: 2

Views: 129

Answers (2)

Lanorkin
Lanorkin

Reputation: 7514

You can not do it for clear reason. Let's assume this line of code will work:

 List<EntityBase<Int32>> listOfEntityBases = (List<EntityBase<Int32>>)obj;

This means that after that line you can do say following

listOfEntityBases.Add(new EntityBase<Int32>());

but actually this line in the same time will add EntityBase<Int32> object to your obj of type List<ClassA> - which is definitely InvalidCast.

So, you just cannot declare the same variable as List<ClassA> and List<EntityBase<Int32>> in the same time.

Though, it is easily allowed for IEnumerable<T> as you can not add new values for such collection.

And that's why they have in and out in generics declaration.

Upvotes: 2

Dennis
Dennis

Reputation: 37780

You can't do cast this way, because:

  • covariance in C# isn't working for classes;
  • interfaces IList<T> and ICollection<T> aren't covariant.

The only option you can do here (except making a copy of a list) is a casting to IEnumerabe<T>:

var listOfEntityBases = (IEnumerable<EntityBase<Int32>>)obj;

Upvotes: 0

Related Questions