Passing embedded template types: cannot be converted from implementation to interface

Can someone explain to me why this is not true in C #:

namespace NamespaceA { public class ClassA<T1> { T1 mT1; public T1 Type1 { get { return mT1; } } } public class IOForClassA { public interface ICanOutput { void OutputFunction(); } public static void Output(ClassA<ICanOutput> aClassA_WithOutputCapabilities) { aClassA_WithOutputCapabilities.Type1.OutputFunction(); } } } namespace NamespaceB { public class ClassB { public class OutputableClassA : NamespaceA.IOForClassA.ICanOutput { public void OutputFunction() { } } public ClassB() { NamespaceA.ClassA<OutputableClassA> aOutputableA = new NamespaceA.ClassA<OutputableClassA>(); NamespaceA.IOForClassA.Output(aOutputableA); } } } 

This will result in a compilation error:

Argument 1: cannot be converted from "NamespaceA.ClassA" <"NamespaceB.ClassB.OutputableClassA"> "to the namespace A..ClassA" <"NamespaceA.IOForClassA.ICanOutput"> "

... but NamespaceB.ClassB.OutputableClassA implements NameSpaceA.IoForClassA.ICanOutput, so I don’t understand why this is the problem ...

I am trying to allow the user to create ClassA of any type that he wishes. However, if they want ClassA to be "deducible," its template type must implement a specific interface.

+1
source share
3 answers

@syazdani correctly says that this is a covariance problem (and he cites a useful article), but his example does not use covariance that would achieve what you are looking for. Although his answer is correct (and most likely preferred, since it has the added benefit of having the actual type if you need it in the Output method), I decided that I would show you how you could do this using the covariant interface this will help you in any other case when you can use them:

 namespace NamespaceA { public interface IClassA<out T1> { T1 Type1 { get; } } public class ClassA<T1> : IClassA<T1> { T1 mT1; public T1 Type1 { get { return mT1; } } } public class IOForClassA { public interface ICanOutput { void OutputFunction(); } public static void Output(IClassA<ICanOutput> aClassA_WithOutputCapabilities) { aClassA_WithOutputCapabilities.Type1.OutputFunction(); } } } namespace NamespaceB { public class ClassB { public class OutputableClassA : NamespaceA.IOForClassA.ICanOutput { public void OutputFunction() { } } public ClassB() { NamespaceA.ClassA<OutputableClassA> aOutputableA = new NamespaceA.ClassA<OutputableClassA>(); NamespaceA.IOForClassA.Output(aOutputableA); } } } 
0
source

You are faced with the problem of covariance / contravariance . In principle, only interfaces can allow generic types to have a more derived type, and only if they are explicitly specified using the in / out keywords (described in a related article).

When reading your code, it seems that you want to call a famous named member of the class without knowing its type, something that type restrictions might be a little better suited to. You may need to change your design a bit.

 namespace NamespaceA { public class ClassA<T1> where T1 : IOForClassA.ICanOutput { T1 mT1; public T1 Type1 { get { return mT1; } } } public class IOForClassA { public interface ICanOutput { void OutputFunction(); } public static void Output<T>(ClassA<T> aClassA_WithOutputCapabilities) where T : IOForClassA.ICanOutput { aClassA_WithOutputCapabilities.Type1.OutputFunction(); } } } namespace NamespaceB { public class ClassB { public class OutputableClassA : NamespaceA.IOForClassA.ICanOutput { public void OutputFunction() { } } public ClassB() { NamespaceA.ClassA<OutputableClassA> aOutputableA = new NamespaceA.ClassA<OutputableClassA>(); NamespaceA.IOForClassA.Output(aOutputableA); } } } 
+2
source

OutputableClassA is derived from ICanOutput . But this does not mean that ClassA<OutputableClassA> also derived from ClassA<ICanOutput> . This is why your code is not working.

Link Covariance and contravariance in general may be useful.

0
source

All Articles