Click here to Skip to main content
15,887,266 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to dig around generics for a bit now, and do not understand the following example:
interface IBaseObject
{
}
interface ITest<T> where T : class, IBaseObject
{
}
abstract class Test<T> : ITest<T> where T : class, IBaseObject
{
}
class BaseObject : IBaseObject
{
}
class ChildObject : BaseObject
{
}
class Specialized : Test<ChildObject>
{
}

class Program
{
    static void Main(string[] args)
    {
        ITest<IBaseObject> test = new Specialized() as ITest<IBaseObject>;
    }
}


ITest<IBaseObject> test
is null.

What I have tried:

I understand, that there is something wrong with this code, but cannot get any idea what it can be. Is it even possible to cast down specialized object to generic interface?
Thanks
Posted
Updated 1-Mar-18 8:12am

1 solution

Covariance and Contravariance in Generics | Microsoft Docs[^]

It's not a simple topic. :)

Imagine a world where I<Derived> was equivalent to I<Base>. That would mean that the following code would work:
C#
class Base { }
class Derived : Base { }
class OtherDerived : Base { }

List<Derived> list = new List<Derived>();
IList<Base> baseList = list;
baseList.Add(new OtherDerived());

Now the list is broken - it can only contain Derived objects, but we've managed to sneak a OtherDerived instance into it.

For your sample to work, your ITest<T> interface needs to be covariant:
C#
interface ITest<out T> where T : class, IBaseObject
{
}

With that one change in place, your code will work as expected.

However, your interface will now be subject to the restrictions placed on a covariant interface: you cannot use the type parameter as a method parameter, not even an out parameter; nor can you use it as the type of a writeable property.
 
Share this answer
 
v2
Comments
OriginalGriff 1-Mar-18 14:19pm    
Spot on! :thumbsup:
csrss 1-Mar-18 14:22pm    
So it seems then I cannot use current design, because interface (ITest) uses T as in and out both. Thanks
Richard Deeming 1-Mar-18 14:28pm    
Depending on how you use it, and what you're intending to do with the ITest<Base>, you might be able to split the interface into two, or possibly three, parts: a covariant part, a contravariant part, and an invariant part.

For example, IReadOnlyList<T>[^] provides a covariant version of the IList<T>[^] interface.
csrss 1-Mar-18 14:36pm    
Richard, thank you a lot :)
I actually changed my design just a little bit by introducing additional non-generic interface and it solved the problem.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900