tags:

views:

144

answers:

5

Hi, I'm having the following interfaces:

public interface IBase
{
    int id1 { get; set; }
}

public interface IDerived : IBase
{
    int id2 { get; set; }
}

And the following (sample) program:

class Program
{
    static void Main(string[] args)
    {
        IList<IDerived> derived = null;
        Check(derived);
    }

    static void Check(IList<IBase> base)
    {
    }
}

I'm getting this compliation error: cannot convert from 'System.Collections.Generic.IList<IDerived>' to 'System.Collections.Generic.IList<IBase>'

If I'm trying to pass only one instance, and not a list, it's working, so what am I missing here?

Thanks,

+3  A: 

This is due to a lack of covariance on interfaces types in C# 3, C# 4 will allow you to specify covariance and contravariance on interfaces types.

Unfortunately this is one of those things that just doesn't work the way you think it should in C# 3.

Andrew Hare
+2  A: 

This is known as covariance. This should be implemented in c# 4, to an extent.

See: http://stackoverflow.com/questions/245607/how-does-c-4-0-generic-covariance-contra-variance-implmeneted

DLKJ
+2  A: 

An instance of IList<IDerived> is not an instance of IList<IBase>. For one thing, you can't call .Add(new ConcreteBase()) on it. (where ConcreteBase implements IBase)

recursive
calling .Add(new ConcreteBase()) is not the same as passing a "Derived Instance" using a "Base Type" reference.
+3  A: 

You will need to cast the IList items to IBase. Here's an example using Linq extensions:

Check(derived.Cast<IBase>());
jrummell
This seems to work only if I change the "Check" method parameter to IEnumerable<> instead of IList<> (which seems to be a similar issue to the one discussed here...IList<> implements IEnumerable<>).
nirpi
Sorry, still early in the morning...Adding ToList() fixed the problem:Check(derived.Cast<IBase>().ToList());Thanks!
nirpi
A: 

And yet this would work...

 static void Main(string[] args)
 {
  List<IDerived> derived = null;
  Check(derived.ToArray());
 }

 static void Check(IBase[] asdf)
 {
 }

One of several reasons I prefer the raw array [] or IEnumerable<> for interfaces both on arguments and return values. But if you prefer using List/IList you can still do the following:

 static void Main(string[] args)
 {
  IList<IDerived> derived = null;
  Check(derived);
 }

 static void Check<T>(IList<T> asdf) where T : IBase
 {
 }
csharptest.net