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