Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Generic Interfaces casting issue

Tags:

c#

.net

generics

Should this be possible using c# 4 and VS 2010? I am doing some processing on class(es) which implements generic interface(s), and after processing would like to convert the objects to a simpler interface so I can extract certain properties defined by common Interfaces.

interface IMyInterface
{
    public Id { get; set; }
}

interface IFile<T1, T2> where T1 : IMyInterface where T2 : IMyInterface
{
    Int64 prop1 { get; set; }
    T1 t1 { get; set; }
    T2 t2 { get; set; }
}

ClassA : IMyInterface
{
    ... Implement some properties plus interface
    public Id { get; set; }
}

ClassB : IMyInterface
{
    ... Implement some properties plus interface
    public Id { get; set; }
}

For example this class has ClassX and ClassY which I want to be certain types for processing/saving, but after that I only want to extract common properties like an ID which is common amongst all classes that Implement this generic Interface (other properties are not common in t1, t1)

ClassSomething : IFile<ClassA, ClassB>
{
    ... Implement properties plus interface 
    public ClassX t1 
    { get {}   set {} }
    public ClassY t2 
    { get {}   set {} }
}



IList<IFile<TItem1, TItem2>> list = new List<IFile<TItem1, TItem2>>() 
    ClassA ca = new ClassA();
    ... Fill in the interface defined properties
    ... Fill the list with objects of ClassSomething

foreach (IFile<TItem1, TItem2> x in list)
{
    // This fails
    IFile<IMyInterface, IMyInterface> interfaceItem = 
        (IFile<IMyInterface, IMyInterface>)x;
}

The cast of x above (t1 and t2 properties specifically) to the simpler IMyInterface interface fails.

There are quite a few generic interface questions but I didn't see (or recognize?) any solutions.

like image 783
lko Avatar asked Jan 31 '26 20:01

lko


1 Answers

The solution you are looking for is called variance (covariance and contravariance). However your IMyInterface cannot be made either covariant or contravariant in T1 and T2, because it has both public getters and public setters accepting T1 and T2:

interface IAnimal {}
class Dog : IAnimal { public void Bark () ; }
class Cat : IAnimal { public void Meow () ; }

var dogs = new FileImpl<Dog, Dog> () ;
dogs.t1  = new Dog () ;

var file = (IFile<IAnimal, IAnimal>) dogs ; // if this were OK...
file.t1  = new Cat () ;                     // this would have to work
dogs.t1.Bark () ;                           // oops, t1 is a cat now
like image 172
Anton Tykhyy Avatar answered Feb 03 '26 08:02

Anton Tykhyy