How to Correctly Cast a Class to an Abstract Class When Using Type Generics

How to correctly cast a class to an abstract class when using type generics?

This is a very frequently asked question. Let's rename your types:

abstract class Fruit { }                    // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { } // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> { } // was LoginView

Your question now is:

I have a BowlOfApples, which inherits from FruitBowl<Apple>. Why can I not use it as a FruitBowl<Fruit>? An apple is a fruit, so a bowl of apples is a bowl of fruit.

No, it isn't. You can put a banana in a bowl of fruit, but you can't put a banana in a bowl of apples, and therefore a bowl of apples is not a bowl of fruit. (And by similar argument, a bowl of fruit is not a bowl of apples either.) Since the operations you can legally perform on the two types are different, they cannot be compatible.

Here is a photo of StackOverflow legend Jon Skeet demonstrating this fact:

Sample Image

The feature you want is called generic contravariance, and it is supported only on interfaces and delegate types when the compiler can prove that the variance is safe, and when the varying type is a reference type. For example, you can use an IEnumerable<Apple> in a context where IEnumerable<Fruit> is needed because the compiler can verify that there is no way that you can put a Banana into a sequence of fruit.

Do a search on "C# covariance and contravariance" on this site or on the web and you'll find many more details about how this feature works. In particular, my series of articles on how we designed and implemented this feature in C# 4 starts here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx

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.

Can't cast derived type to base abstract class with type parameter

This is neither a compiler defect nor a deliberate decision. Type parameters on generic classes are neither covariant nor contravariant, ie there is no inheritance relationship between specializations of the same generic class. From the docs:

In the .NET Framework version 4, variant type parameters are restricted to generic interface and generic delegate types.

Which means that the following code will compile, because it uses an interface instead of an abstract class:

interface IWheel
{
}

class CarWheel : IWheel
{
}

interface IVehicleBase<T>
{
}

class Car : IVehicleBase<CarWheel>
{
}

class VehicleFactory
{
public static IVehicleBase<T> GetNew<T>()
{
if (typeof(T) == typeof(CarWheel))
{
return (IVehicleBase<T>)new Car();
}
else
{
throw new NotSupportedException();
}
}
}

Check "Covariance and Contravariance in Generics" for more info and examples.

There is also a Covariance and Contravariance FAQ at the C# FAQ blog with more info, and an 11-part series! on the subject by Eric Lippert

How to override method from abstract class that uses generics for typing?

Based on your requirement, can you try

interface Model {}

abstract class WebModel {
public static getWebModelFromDbModel<A extends WebModel, B extends Model>(dBModel: B): A {
throw 'some error'
}
}

class concreteWebModel extends WebModel {
public static getWebModelFromDbModel<A extends WebModel=concreteWebModel>(dbModel: Model): A & concreteWebModel {
return '' as unknown as A&concreteWebModel;
}

log() {}
}

let s = concreteWebModel.getWebModelFromDbModel(1 as any as Model);
s.log()

You can also remove generic type A, if you don't want to cast

interface Model {}

abstract class WebModel {
public static getWebModelFromDbModel<B extends Model>(dBModel: B): WebModel {
throw 'some error'
}
}

class concreteWebModel extends WebModel {
public static getWebModelFromDbModel<B extends Model>(dBModel: B): concreteWebModel {
return new concreteWebModel();
}

log() {}
}

let s = concreteWebModel.getWebModelFromDbModel(1 as any as Model);
s.log()

Returning a generic object on Java from abstract class

What you are doing is not a good design. You are using an Object type field from the superclass while you only can know it's actual (needed) type in the subclass. If you only know that in the subclass, declare that variable in the subclass. Not even to mention that your fields are not private.

How about:

public abstract class QueryMatch {

private String key;

public QueryMatch(String key) {
this.key = key;
}

public String getKey() {
return key;
}

public abstract void addMatch(String match);
}

public class QueryMatchOr extends QueryMatch {

private ArrayList<String> input;

public QueryMatchOr() {
super("title");
input = new ArrayList<String>();
}

public void addMatch(String match) {
input.add(match);
}
}

If you need the getValue() method in the superclass, you really should make it generic:

public abstract class QueryMatch<T> {

private String key;

public QueryMatch(String key) {
this.key = key;
}

public String getKey() {
return key;
}

public abstract void addMatch(String match);

public abstract T getValue();
}

public class QueryMatchOr extends QueryMatch<ArrayList<String>> {

private ArrayList<String> input;

public QueryMatchOr() {
super("title");
input = new ArrayList<String>();
}

public void addMatch(String match) {
input.add(match);
}

public ArrayList<String> getValue(String match) {
input;
}
}

C# cast generic T in abstract class T to dynamic

To do what you want to do you are going to need to use a Contravariant interface

public class Program
{
static void Main()
{
var m = new Helper();
m.Add(new ConcreteClass());

m.Process();
}

class Helper
{
List<IAbstractClass<OtherClassBase>> data = new List<IAbstractClass<OtherClassBase>>();

public void Add(IAbstractClass<OtherClassBase> thing)
{
this.data.Add(thing);
}

public void Process()
{
foreach(var c in data.Where(x => x.ShouldBeProcessed()))
{
var b = c.Invoke();
Console.WriteLine(b.Question);
var castData = b as OtherClass;
if (castData != null)
Console.WriteLine(castData.Answer);
}
}
}

public interface IAbstractClass<out T>
{
bool ShouldBeProcessed();
T Invoke();
}

abstract class AbstractClass<T> : IAbstractClass<T>
{
public bool ShouldBeProcessed()
{
return true;
}

public abstract T Invoke();
}

class ConcreteClass : AbstractClass<OtherClass>
{
public override OtherClass Invoke()
{
return new OtherClass();
}
}

class OtherClassBase
{
public string Question { get { return "What is the answer to life, universe, and everything?"; } }
}

class OtherClass : OtherClassBase
{
public int Answer { get { return 42; } }
}
}

You do not need to tell Add what kind of class you are passing it, all that matters is it derives from the type specified. You could do public void Add(IAbstractClass<object> thing) and every class would work, but Invoke() would only return objects inside the foreach loop.

You need to figure out what is the most derived class you want Invoke() to return and that is what you set as the type in the list.

casting to an abstract generic base class

It is hard to write strongly typed code that goes from base class to one of derived classes that are generic. One option is to use dynamic instead of strongly typed code.

Another option is to have non-generic base class or interface unless you need to work with elements of particular type:

interface IHasTheStuff
{
bool HaveStuff();
}

public abstract class BaseController<TElement> : IHasTheStuff, Controller ...
{
...
public bool HaveStuff() { return Stuff != null;}
}

And than when you have just controller cast to that interface:

Controller justController...
if (((IHasTheStuff)justController).HaveStuff())...

Casting a generic superclass to a subclass

I seems rather questionable design to have a mutual dependency between the food and its storage. A unidirectional depedency would simplify the generics greatly:

class Food { ... }
class FoodStorage<F extends Food> {
void setFood(F f);
}

But if you insist on the mutual dependency, you can do it without a cast as follows:

abstract class Food<F extends Food<F, S>, S extends FoodStorage<F, S>> {
abstract F getThis();
abstract S getStorage();

void save() {
getStorage().setFood(getThis());
}
}
abstract class FoodStorage<F extends Food<F, S>, S extends FoodStorage<F, S>> {
abstract void setFood(F food);
}


Related Topics



Leave a reply



Submit