0

I've an interface which states:

public interface IMyType<T> where T: IMySubType {
    event EventHandler<IMyType<T>, EventArgs<T>> OnSomething;
    IEnumerable<T> AvailableThings{get;}
    void Start();
}

I've a List<IMyType<IMySubType>>, how can I add a IMyType<SubTypeImplementation> to this list? (SubTypeImplementation herits from the IMySubType interface.

I tried to put my Tgeneric type as covariant, but it doesn't seems to work with an interface using this type as event(not sure to know why).

So, how can I store, iterate and call the start method on each element of the list?

Because currently my other alternative is to create a new interface without the genericity, and make a double implementation(because in most case I need to have this genericity.

J4N
  • 19,480
  • 39
  • 187
  • 340

2 Answers2

0

How about this:

public interface IMyType { }

public interface IMyType<T> : IMyType where T : IMySubType
{
    event EventHandler<IMyType<T>, EventArgs<T>> OnSomething;
    IEnumerable<T> AvailableThings{get;}
    void Start();
}

Your list would be of type List<IMyType>:

List<IMyType> myList = new List<IMyType>();
myList.Add(implementation1); // implementation1 is of type IMyType<SubTypeImplementation>
myList.Add(implementation2); // implementation2 is of type IMyType<SubTypeImplementation2>

Of course, the drawback would be that you will need to cast each element on the list in order to use it:

var impl = (IMyType<SubTypeImplementation>)list[0];
impl.Start();

Anyway, I wouldn't use generics in this situation.

My IMyType would look like this:

public interface IMyType
{
     event EventHandler<IMySubType, EventArgs<IMySubType>> OnSomething;
     IEnumerable<IMySubType> AvailableThings { get; }
     void Start();
}
Matias Cicero
  • 25,439
  • 13
  • 82
  • 154
  • Well, I cannot know which generic type I receive – J4N Nov 09 '15 at 15:00
  • Edit bis: Like I said, the main use of this class is to have the same behavior for different kind of sub items. But in my new case, I need to be able to get them anonymously and I wanted to know if there was a way to do it – J4N Nov 09 '15 at 15:01
  • @J4N Polymorphism doesn't work on generics. `IEnumerable`, for example, is not the same type as (nor does it inherit from) `IEnumerable`. This is the only way I see of working around your problem. – Matias Cicero Nov 09 '15 at 15:02
  • @J4N Lists do not support covariance. See [C# - Assigning List as List](http://stackoverflow.com/questions/2033912/c-sharp-variance-problem-assigning-listderived-as-listbase) – Matias Cicero Nov 09 '15 at 15:07
  • Any other IEnumerable type that would support it? – J4N Nov 09 '15 at 15:19
0

how can I add an IMyType<SubTypeImplementation> to this list?

IMyType needs to be covariant for this to work. Being covariant means that the generic type can only be included in the output of functions. Since your interface includes an EventHandler that takes the generic type as part of the input, your interface cannot be covariant.

Let's change you interface names to understand why. Suppose you run a zoo and want to distinguish "view-only" cages from "normal" cages. So you have two interfaces:

IViewOnlyCage<out T>
{
    public T View();
}

ICage<T>
{
    public Add(T animal);
}

Now consider two "lists" of cages:

List<IViewOnlyCage<IAnimal>> list1;
List<ICage<IAnimal>> list2;

And I populate the lists as such:

list1.Add(new Cage<Tiger>());
list1.Add(new Cage<Deer>());

In the first case, a list of view-only cages is perfectly reasonable. Each cage contains some type of animal, so there's no danger of the two animals ending up together.

But consider the second - with an Add method I could do this:

list2.Add(new Cage<Tiger>());

ICage<IAnimal> cage = list2[0];  // a reference to the tiger cage
cage.Add(new Deer());  //uh-oh... bad news for the deer

Since your interface contains indirect inputs, something like this would be possible:

List<IMyType<IMySubType>> list = new List<IMyType<IMySubType>>();

list.Add(new IMyType<SubTypeImplementation>());

IMyType<IMySubType> item = list[0];  // seems OK

item.OnSomething += new EventHandler(IMyType<SecondSubType>, EventArgs<SecondSubType>);   

but the actual generic type is SubTypeImplementation, not SecondSubType, so you have a type conflict.

The easiest changes seems to be to move the event handler to a different interface. You can then make IMyType covariant and have a List<IMyType<IMySubType>>.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • okay. Is there a workaround to have event that include the generic type? – J4N Nov 09 '15 at 15:17
  • @J4N Not that will make `IMyType` covariant. You'll have to live with lists of more specific types. – D Stanley Nov 09 '15 at 15:30
  • Well, This doesn't solve my issue unfortunately, I need to get the specific version in many case. Also, I understand the boxing issue, but in my case, I don't see how I can have such issue, since I always use this type as "output", and the only way I could use it is to be "more generic". I don't return list of anything, I use a list to store the generic version of my class – J4N Nov 10 '15 at 07:04
  • But the settable event handler allows an input of a "derived" type, which is not allowed. I'll add some options, but no magic bullets. – D Stanley Nov 10 '15 at 14:03