How do I declare and use generic interfaces (see namespace Sample2) to work in the same way as with classes in namespace Sample1?
I know there is a workaround (see namespace Sample2Modified) but that is not what I'm trying to achieve.
When using classes, this works fine:
namespace Sample1
{
    public class ClassContainer<T1, T2>
        where T1 : T2
    { }
    public class ClassParent
    { }
    public class ClassChild : ClassParent
    { }
    public class ClassSampleDoesWork<TItem>
        where TItem : ClassParent
    {
        ClassContainer<IEnumerable<TItem>, IEnumerable<ClassParent>> SomeProperty { get; set; }
    }
}
However, with interfaces the compiler gives this warning when declaring the property in ClassSampleDoesNotWork:
Error 16 The type 'System.Collections.Generic.IEnumerable<TItem>'
cannot be used as type parameter 'T1' in the generic type or method
'Sample2.IInterfaceContainer<T1,T2>'. There is no implicit reference
conversion from 'System.Collections.Generic.IEnumerable<TItem>' to
'System.Collections.Generic.IEnumerable<Sample2.IInterfaceParent>'.
Code:
namespace Sample2
{
    public interface IInterfaceContainer<T1, T2>
        where T1 : T2
    { }
    public interface IInterfaceParent
    { }
    public interface IInterfaceChild : IInterfaceParent
    { }
    public class ClassSampleDoesNotWork<TItem>
        where TItem : IInterfaceParent
    {
        IInterfaceContainer<IEnumerable<TItem>, IEnumerable<IInterfaceParent>> SomeProperty { get; set; }
    }
}
If I modify the class to have TEnumerableOfItem instead of TItem, it works:
namespace Sample2Modified
{
    public interface IInterfaceContainer<T1, T2>
        where T1 : T2
    { }
    public interface IInterfaceParent
    { }
    public interface IInterfaceChild : IInterfaceParent
    { }
    public class ClassSampleModifiedDoesWork<TEnumerableOfItem>
        where TEnumerableOfItem : IEnumerable<IInterfaceParent>
    {
        IInterfaceContainer<TEnumerableOfItem, IEnumerable<IInterfaceParent>> SomeProperty { get; set; }
    }
}
                Try to add class constraint to the TItem:
namespace Sample2
{
    public interface IInterfaceContainer<T1, T2>            
        where T1 : T2
    { }
    public interface IInterfaceParent
    { }
    public interface IInterfaceChild : IInterfaceParent
    { }
    public class ClassSampleDoesNotWork<TItem>
        where TItem : class, IInterfaceParent
    {
        IInterfaceContainer<IEnumerable<TItem>, IEnumerable<IInterfaceParent>> SomeProperty { get; set; }
    }
}
This works because variance only works for reference-types (or there is an identity conversion). It isn't known that TItem is reference type, unless you add : class.
Read this article for more information.
Here is a sample code to demonstrate this behavior:
IEnumerable<Object> items = new List<int>(); // Compiler error.
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With