views:

352

answers:

2

Hi, I have the following class structure:

public class A : AInterface { }
public interface AInterface { }

public class B<T> : BInterface<T> where T : AInterface 
{
    public T Element { get; set; }
}
public interface BInterface<T> where T : AInterface 
{
    T Element { get; set; }
}

public class Y : B<A> { }

public class Z<T> where T : BInterface<AInterface> {}

public class Test
{
    public Test()
    {
        Z<Y> z = new Z<Y>();
    }
}

This gives me the following compile erorr in C# 4.0. The type 'Test.Y' cannot be used as type parameter 'T' in the generic type or method 'Test.Z'. There is no implicit reference conversion from 'Test.Y' to 'Test.BInterface'.

I though the covariance in generics should make this work? Any help will be appreciated.

+1  A: 

I think you are missing the out keyword. Try adding it to the following lines:

public interface BInterface<out T> where T : AInterface { }
public class Z<out T> where T : BInterface<AInterface> {}

I'm not sure if it's needed in both places, though.

Greg
Classes cannot be variant, so you can't add "out" or "in" for generic parameters in classes.
Alexandra Rusina
+3  A: 

Generic parameters in interfaces are invariant by default, you need to explicitly specify whether you want a particular generic parameter to be covariant or contravariant. Basically, in your example you need to add "out" keyword to the interface declaration:

public interface BInterface<out T> where T : AInterface { } 

You can find more info about creating variant interfaces on MSDN: Creating Variant Generic Interfaces (C# and Visual Basic).

Alexandra Rusina
Thanks Alexandra. This would certainly help if T is a return parameter. In my case I've missed an important detail in the B and BInterface: public class B<T> : BInterface<T> where T : AInterface { public T Element { get; set; } } public interface BInterface<T> where T : AInterface { T Element { get; set; } }out will not work since T is both in and out. Any suggestions?
roger
Yes, if you have a generic constraint on a type parameter, you can't make it covariant. This is by design. http://msdn.microsoft.com/en-us/library/dd469487(VS.100).aspx "In a generic interface, a type parameter can be declared covariant if it satisfies the following conditions: 1) The type parameter is used only as a return type of interface methods and not used as a type of method arguments. 2) The type parameter is not used as a generic constraint for the interface methods."
Alexandra Rusina