Generics and Casting - Cannot Cast Inherited Class to Base Class

Generics and casting - cannot cast inherited class to base class

RepositoryBase<EntityBase> is not a base class of MyEntityRepository. You're looking for generic variance which exists in C# to a limited extent, but wouldn't apply here.

Suppose your RepositoryBase<T> class had a method like this:

void Add(T entity) { ... }

Now consider:

MyEntityRepository myEntityRepo = GetMyEntityRepo(); // whatever
RepositoryBase<EntityBase> baseRepo = (RepositoryBase<EntityBase>)myEntityRepo;
baseRepo.Add(new OtherEntity(...));

Now you've added a different kind of entity to a MyEntityRepository... and that can't be right.

Basically, generic variance is only safe in certain situations. In particular generic covariance (which is what you're describing here) is only safe when you only ever get values "out" of the API; generic contravariance (which works the other way round) is only safe when you only ever put values "into" the API (e.g. a general comparison which can compare any two shapes by area can be considered as a comparison of squares).

In C# 4 this is available for generic interfaces and generic delegates, not classes - and only with reference types. See MSDN for further information, read <plug>read C# in Depth, 2nd edition, chapter 13</plug> or Eric Lippert's blog series on the topic. Also, I gave a one hour talk about this at NDC in July 2010 - the video is available here.

C# generic inheritance, base class casting

If you make an explicit cast:

var castRes = A<XBase>(a);

then you will see the following error:

Unable to cast object of type '' to type '`

Why? In my view, it is better to understand using real world example. I've renamed classes based on this explanation. There are comments which maps explanations to your classes in question.

Abstractions:

// XBase 
public class Animal { }

// class ImplementorX : XBase {public int a;}
public class Bird : Animal
{
public string WingColor { get; set; }
}

// interface A<T> where T : XBase
public interface IHat<T> where T : Animal
{
void Hide(T param);

T Pull();
}

Concrete implementations:

// class Implementor : A<Implementor.ImplementorX > 
public class Peacock : IHat<Bird>
{
// void Method(ImplementorX param) {}
void IHat<Bird>.Hide(Bird param)
{ }

public Bird Pull()
{ }
}

and how it can be called:

public static void Main(string[] args)
{
Peacock peacockHat = new Peacock();

IHat<Animal> animalHat = (IHat<Animal>) peacockHat; // runtime error 'Unable to cast
// object of type 'HelloWorld.Peacock' to type 'HelloWorld.IHat`1

// because
animalHat.Hide(new Dolphin()); // Hide a dolphin in a peacock hat?
}

So we cannot hide hat of Peacock from Dolphin. It is not okay. CLR prevents us from making inappropriate actions.

In short:

In short, imagine you have two animals such as Wolf and Sheep. And these classes implements IAnimal interface:

public interface IAnimal
{ }

public class Wolf: IAnimal
{ }

public class Sheep : IAnimal
{ }

So Sheep, Wolf classes implement the inherited interface IAnimal:

            IAnimal
/ \
/ \
Sheep Wolf

And then these animals can be put in cage:

public class Cage<T> where T : IAnimal
{
public void Put(T animal)
{ }
}

Then you create a cage for Sheep. After that somebody wants to cast Sheep cage to IAnimal:

Cage<Sheep> sheepCage = new Cage<Sheep>();
sheepCage.Put(new Sheep());

Cage<IAnimal> animalCage = (Cage<Wolf>)sheepCage; // compile error
// if there were no error, then you will be able to do:
animalCage.Put(new Wolf()); // it is not good idea

Cast Generic Derived to Generic Base

You cannot cast a Generic<Derived> to a Generic<Base>.

Just imagine if you could. You have a List<Wolf> and cast it to a List<Animal>. Now you could .Add() a Sheep to your List<Animal>. But wait... now your List<Wolf> contains a Sheep. What a mess.

This would only work out if you could make sure that the thing you cast to is read-only in all possible forms. This is was co- and contravariance is all about. It only works for interfaces though.

Casting generic class with inheritance

You cannot do that in C#. You can only do it by introducing a generic interface on top level which is co-variant on the generic parameter using out like:

public class Segment<K> : ISegment<K> where K : SomeStructure{...}

While your interface should look like:

public interface ISegment<out T>
{

}

and your code for casting will use interface type now :

data as ISegment<SomeStructure>

check this demo fiddle as example.

Derived class from generic abstract class and casting error?

Neither of the answers given so far are correct. They are right that the problem is that your type is not covariant, but wrong in the proposed solution, which is illegal and will not compile.

Your example is very complicated, so let's look at a simpler example. If you have:

class Animal {}
class Giraffe : Animal {}
class Tiger : Animal {}

Then this conversion is legal:

IEnumerable<Giraffe> giraffes = new List<Giraffe>() { new Giraffe() };
IEnumerable<Animal> animals = giraffes;

This is a covariant conversion. A covariant conversion is a conversion where the justification for the conversion is "Giraffe is convertible to animal, therefore a sequence of giraffes is convertible to a sequence of animals". That is, a covariant conversion is one where an existing conversion justifies a more complex generic conversion.

However, this conversion is not legal:

IList<Giraffe> giraffes = new List<Giraffe>() { new Giraffe() };
IList<Animal> animals = giraffes;

Why is this conversion not allowed? Because it can be abused! We can now say

animals.Add(new Tiger());

The list of animals is still a list of giraffes. You cannot add a tiger to a list of giraffes. You can add a tiger to a list of animals. Therefore, "list of giraffes" is not a subtype of "list of animals", even though giraffe is a subtype of animal. IEnumerable<T> allows covariance because there is no way to insert a tiger into a sequence of giraffes. IList<T> does not allow covariance because there is a way to abuse it.

C# allows covariant conversions like the one you want under the following circumstances:

  • The generic type arguments involved in the covariant conversion -- that is, the stuff in the <> --- must all be reference types. You cannot, say, convert List<int> to IEnumerable<object> even though int is convertible to object. int is not a reference type.

  • The "outer" generic type that you are converting to must be an interface or a delegate type, not a class or a struct.

  • The interface or delegate must be declared as supporting covariance, and the compiler must be able to check that the declaration is valid and never produces a situation where you can put a tiger into a box that can only hold giraffes.

I do not know offhand how to redo your complicated logic to make it work the way you want. You might want to go with a less complicated solution that does not rely on generics so much.

C# Cannot convert from `Inherited Class` to `Base Class`

You are making the mistake of assuming that if Car inherits from Transport then Wrapper<Car> also inherits from Wrapper<Transport>. It does not.

You need to define IWrapper<out T> and use that for your list. Then this kind of covariance can work.

Kotlin Generic Inheritence how to cast to inherited object

Actually, a better solution in my opinion A should be generic (as A is abstract and one of quite important thing is the type of boxed value). Then, you could do following:

abstract class A<T: Animal> {
lateinit var x: T
fun defineStuff() {
x = Factory().createFor(getAnimalType())
}
abstract fun getAnimalType(): Class<T>
}

class DogA: A<Dog>() {
override fun getAnimalType() = Dog::class.java
}

Convert Generic Class to Its Inherited Class

Even though your Template class inherits from Template<double>, it's not the same. Conside you will change the defintion of Template as follows:

public class Template : Template<double>
{
public int AddedMember { get; set; }
}

Now, you try to execute the previous code. You're trying to convert a class with some properties, to a class with more properties - you'll access to incorect places in the memory!

You always can convert a class to its base class, because the drived class contains all the base class' memebers. So, explicit conversion is not needed. However, when you're trying to convert a base class to a drived class, the convert will success only if the base class variable points to an instance of the drived class, and so, all the memebers of the drived class are exist. If no, an InvalidCastException will thrown at runtime. So, explicit cast is required (because one of the guidlines why to use an explicit cast is to use an explicit cast if the cast may fail).

So, if you'll change your code so the variable a (of type Template<double>), the convert will success:

Template<double> a = new Template();
Template b = (Template)a; // No exception will thrown

The last code will success beacuse the variable a points to an instance of Template (and not of Template<double>), so we sure (at runtime) that all the members of Template is exist and no error will occur.

Edit:

After you said your requirements, I can help you. What you want? you want to enable convert of `Template` to `Template` - this is possible with [user-defined conversions](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/conversion-operators).

But, custom conversions between drived class and base class are not allowed. So, there are two solutions:

  1. Template won't inherit from Template<double>, as follows:
    public class Template<T>
{
public T Value { get; set; }
}

public class Template
{
public double Value { get; set; }

public static explicit operator Template(Template<double> generic) // Or implicit instead of explicit
{
return new Template { Value = generic.Value };
}
}

var generic = new Template<double> { Value = 1234.56 };
var nongeneric = (Template)generic; // Or Template nongeneric = generic; if the conversion defined as implicit

  1. You won't define a custom conversion, and instead, you'll define a regular method (I defined a constructor):
    public class Template<T>
{
public T Value { get; set; }
}

public class Template : Template<double>
{
public Template(Template<double> generic)
{
this.Value = generic.Value;
}
}

var generic = new Template<double> { Value = 1234.56 };
var nongeneric = new Template(generic);

Casting Generic base object to derived type

A reference declared as BaseSettings<T> may or may not refer to an actual instance of Settings1Manager. That's how inheritance works. In fact though, what you're doing is casting a base type reference that's actually referring to an object that you've just confirmed actually is of the derived type.

settings as Settings1Manager will compile, because as will just return null if the cast fails. You and I know that particular cast won't fail, but the compiler just follows its rules.

if (typeof(Settings1Manager).IsAssignableFrom(settings.GetType()))
{
return WriteSettings1ManagerToNetwork(settings as Settings1Manager);
}

This works too, because you can cast anything to object and you can cast object to anything. But you don't want people seeing your name on code that looks like this.

return WriteSettings1ManagerToFile((Settings1Manager)(object)settings);


Related Topics



Leave a reply



Submit