此代码是在visual studio中编译的,它的用法是什么
public class MyClass<T>
where T : MyClass<T>
注意where T : MyClass<T>
答案 0 :(得分:4)
这是recurring template pattern,通常用于基类可以静态引用其实际类型。这样做是为了保护类型安全性,以便基类中引用的参数或返回值跟踪层次结构中的当前类型,例如
public class Animal<T> where T : Animal<T>
{
public abstract T GiveBirth();
}
public class Cat : Animal<Cat>
{
public override Cat GiveBirth() { return new Cat(); }
}
如果没有type参数,Animal
基类方法只能将GiveBirth
的返回类型定义为Animal
,这可能会降低客户端的类型安全性。
如果你控制整个层次结构并且可以确保类提供正确的类型参数,它可能是可以接受的,但请注意它可能被滥用,例如。
public class Cat : Animal<Dog> { ... }
另一个缺点是任何客户端都需要考虑泛型类型参数,如果他们想要应用于基类,例如。
public static void Feed<T>(Animal<T> animal) where T : Animal<T> { ... }
public static void Feed<T>(T animal) where T : Animal<T> { ... }
答案 1 :(得分:2)
这是一个奇怪的重复模式的例子。 Eric Lippert对此有an excellent article,包括为什么通常应该避免它。
它可能会像这样扩展:
public class MyChild : MyClass<MyChild>
这种模式并不能确定为什么你想要这种泛型。这与大多数泛型/约束不同,例如。如果我有List<Giraffe>
我可以看到这种关系;如果我有MyGeneric<T, U> where T : IComparer<U>
,我可以看到T
会做什么。对于T : MyClass<T>
,我对这里的关系或用法没有任何暗示。也许还有......
abstract T Instance { get; }
...在MyChild
的情况下,您希望MyChild
具有更强的输入效果。
作为一个例子,为什么这不是很好,你可能有MyOtherClass : MyClass<MyChild>
,或者你可能有MyGrandchild : MyChild
,这两者都不是你想要强制执行的。
答案 2 :(得分:1)
对于只有抽象基类型的单层继承的类型,使用所描述的模式将使抽象基类型包含在派生类型的任何成员上调用时将包含的方法返回该派生类型的成员。这可能是一个有用的设计功能,允许比其他方式更干净的调用者代码。这种设计的最大问题是,由于.NET不支持协变泛型类参数,因此该方法不会使用多层继承。
给定abstract class AnimalBase<T> where T:AnimalBase<T>
,使用方法T Clone()
和class Cat: AnimalBase<Cat>
,代码可以说var newCat = someCat.Clone(); newCat.Meow();
而不必说var newCat = (Cat)(someCat.Clone()); newCat.Meow();
。不幸的是,由于只有SiameseCat
的唯一方法,因此无法从Cat
正确派生mySiameseCat.Clone()
类型。返回SiameseCat
将SiameseCat
派生AnimalBase<SiameseCat>
,但这会阻止它派生自Cat
。
如果不是将类约束到它自己的类型,而是定义一个通用接口并限制它,可以避免这样的困难。在SiameseCat
实施Cat
时IAnimal<SiameseCat>
导出IAnimal<SiameseCat>
会有问题。此外,接口是协变的,因此实现IAnimal<Cat>
的类型也可以隐式地实现Cat
[如果{{1}}是一个没有实现接口本身的抽象类型]。该类的每个派生都必须提供自己的任何方法的实现,其返回值随泛型类型参数而变化,但从调用者的角度来看,接口类型可以与派生类完美地表现。
答案 3 :(得分:0)
它看起来是保证类型是二维的(如果这个术语在这里有意义的话)。
例如:Node<int>
最终会成为Node<Node<int>>
。