Polymorphism in general type parameters

I am trying to use polymorphism in generic type parameters in C #. I looked at a few more questions on SO ( 1 , 2 , 3 , 4 , 5 , 6 ), but I still don't understand why this is not working (or even allowed).

Background

I have the following classes:

public class Base { } public class Derived<T> : Base { } public class Foo { } 

and an instance of my derived generic type:

 var derived = new Derived<Foo>(); 

The basics

All statements are true:

 derived is Object derived is Base derived is Derived<Foo> 

Problem

When I try to use my derived class as a type parameter in another generic type, I get some unexpected behavior. Given the following lazy example:

 var lazy = new Lazy<Derived<Foo>>(); 

The following is true:

 lazy is Lazy<Derived<Foo>> 

But they are false when I expected them to be true:

 lazy is Lazy<Object> lazy is Lazy<Base> 

Why is this? Should they be true or did I misunderstand how generics work?

+7
generics polymorphism c #
source share
1 answer

Yes, you misunderstood how the general one works. This is also the biggest limitation on the use of generic types (in fact, you should avoid them as much as possible because of this). If Derived inherits from Base, then it's usually not that Generic<Derived> is Generic<Base> . The exception is covariance and contravariance. If you define your general class as follows:

 public class Generic<out T> {} 

then Generic<Derived> is Generic<Base>

If you define your general class as follows:

 public class Generic<in T> {} 

then Generic<Base> is Generic<Derived> (unexpectedly, yes?).

Why doesn't a simple actor work? Imagine our general class is as follows:

 public class Generic<T> { public void Func1(T input); public T Func2(); } 

Imagine we have a Generic<Derived> object, and we use it as a Generic<Base> . In this case, Func2 works fine - it returns a Derived object, which can be a caster for Base. But Func1 will not work - we have a function that accepts a base object, but the actual object has Func1, which accepts only derivative objects, and not all base derivatives objects, right?

This example explains why input and output inheritance works. If we apply the restriction on the type parameter in the generic class, we fix that the type T can only be returned from properties or functions, but it can never be accepted as a parameter. In this case, our general class is as follows:

 public class Generic<out T> { public T Func2(); } 

As we exaplained in earlier Func2 will work fine if we use a Generic<Derived> object as a Generic<Base> . For the same reason for the class:

 public class Generic<in T> { public void Func1(T input); } 

Func1 will work fine if the Generic<Base> object is used as a Generic<Derived> - in this case we will always pass Func1 Derived objects as parameters, and Dervied is always Base by definition.

+6
source share

All Articles