我在下面的演员中遇到了一些问题:
class A
{
}
class B : A
{
}
class C<T> where T : A
{
protected T property { get; set; }
}
class D : C<B>
{
}
class MainClass
{
public static void Main (string[] args)
{
C<A> x = new D();
// Error CS0029: Cannot implicitly convert type `SampleApp.D' to `SampleApp.C<SampleApp.A>' (CS0029) (SampleApp)
}
}
我不明白为什么这会失败,因为D
比C<A>
宽,因为它实现了C<B>
和B : A
。任何解决方法?
答案 0 :(得分:2)
如果您可以使用C#4.0,则可以编写以下代码。
class A { }
class B : A {}
interface IC<out T> {}
class C<T> :IC<T> where T : A { protected T property { get; set; } }
class D : C<B> {}
class MainClass {
public static void Main()
{
IC<A> x = new D();
}
}
答案 1 :(得分:1)
我们为Animal
命名您的班级A
,为Barker
命名B
,为Dog
命名D
。
实际上C<Animal>
比Dog : C<Barker>
宽。假设您拥有Me
类型的公共属性T
并且可以分配:
C<Animal> a = new Dog();
a.Me = Elephant; // where Elephant inherited from Animal
糟糕! Dog
使用Barker
进行参数化。你见过吠叫大象吗?
您需要声明一些协变接口,以允许将使用更多派生类型参数C<Barker>
实例化的类分配给使用较少派生类型参数C<Animal>
实例化的对象。您可以使用空接口,如@NickW建议的那样,但您将无法对该接口的实例执行某些操作(它是空的!)。所以,让我们这样做:
interface IC<out T>
where T : Animal
{
IEnumerable<T> Parents(); // IEnumerable is covariant
T Me { get; } // no setter
}
class C<T> : IC<T>
where T: Animal
{
// implementation
}
class D : C<Barker>
{
// implementation
}
以上情况仍然不可能,但现在你可以
IC<Animal> a = new Dog();
foreach(var parent in a.Parents)
Console.WriteLine(parent);
Console.WriteLine(a.Me);
答案 2 :(得分:-1)
你不能这样做,因为Generics是实际模板而且它们不像你想用它们做的那样。让我告诉你:
当您说"C<A>"
时,它表示"parameter"
"A"
的通用类。
但
当您说"D"
时,它恰好意味着"D"
!
所以D不等于A的参数的泛型类。你可以在两种类型的ToString函数的结果中看到它(通过使用typeof)。
希望有所帮助
干杯