有人可以向我解释为什么在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);
}
}
}
这将导致编译错误:
参数1:无法转换为'NamespaceA.ClassA'&lt;“NamespaceB.ClassB.OutputableClassA”&gt;“ to NamespaceA.ClassA“&lt;”NamespaceA.IOForClassA.ICanOutput“&gt;”
...但是NamespaceB.ClassB.OutputableClassA实现了NameSpaceA.IoForClassA.ICanOutput,所以我不明白为什么这是一个问题......
我试图允许用户创建他/她希望的任何类型的ClassA。但是,如果他们希望ClassA是“可输出的”,那么其模板化类型必须实现特定的接口。
答案 0 :(得分:2)
您正遇到covariance/contravariance问题。基本上,只有接口可以允许泛型类型具有更多派生类型,并且只有在使用输入/输出关键字明确指定它们时(在链接文章中概述)。
阅读你的代码,似乎你想要在不知道其类型的情况下调用类的已知命名成员,这可能是type constraints可能更适合的类型。你可能不得不稍微改变你的设计。
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);
}
}
}
答案 1 :(得分:0)
OutputableClassA
源自ICanOutput
。但这并不意味着ClassA<OutputableClassA>
也来自ClassA<ICanOutput>
。这就是你的代码无效的原因。
答案 2 :(得分:0)
@syazdani关于它是一个协方差问题是正确的(他链接到一篇有用的文章),但他的例子并没有使用协方差,这将实现你正在寻找的东西。虽然他的答案是正确的(并且可能是优选的,因为它带来了额外的好处,如果您需要将其带入Output
方法,我会告诉您如何使用协变来实现这一点界面,以防它可以帮助您在任何其他情况下使用它们:
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);
}
}
}