我遇到了以下代码,都在一个文件/类中。我遗漏了细节,它是我感兴趣的构造。为什么同一个类有两个不同的声明,它们有什么不同?第二个声明的语法的目的是什么?
public abstract class MyClass
{
...
}
public abstract class MyClass<TMyClass> : MyClass
where TMyClass: MyClass<TMyClass>
{
...
}
答案 0 :(得分:3)
MyClass
- 一个名为MyClass的抽象类。
MyClass<TMyClass> : MyClass
- 一个名为MyClass<>
的抽象泛型类,但具有名为TMyClass
的泛型类型。
如果您重命名类型,则会更容易看到:
public abstract class MyBaseClass
{
...
}
public abstract class MyClass<T> : MyBaseClass
where T: MyClass<T>
{
...
}
答案 1 :(得分:3)
具有不同通用arity的类型(即泛型类型参数的数量,可以是零或更多)被认为与语言完全无关,并且可以具有相同的名称。
这意味着您可以同时拥有课程Foo
,Foo<T>
和Foo<T,U>
;语法将允许编译器确定您指的是哪个。您可以在基础框架中看到这种情况,其中包括Action
,Action<T>
等。
“递归”构造class C<T> where T: C<T>
(来自非泛型C
的继承不会改变任何东西,所以我删除它)是所谓的Curiously Recurring Template Pattern上的C#(CRTP )在C ++中。 Eric Lippert has covered this subject在一篇博客文章中非常清楚,其结论是在实现这一点之前应该考虑两次以上 - 它可以解决的问题,但解决方案也有代价。
答案 2 :(得分:2)
public abstract class MyClass<TMyClass> : MyClass
where TMyClass: MyClass<TMyClass>
{
...
}
是一个继承自MyClass
的类,它采用泛型类型,必须从MyClass<TMyClass>
继承
这是一个更简单的例子,为你做同样的事情
public static void Main()
{
MyClass<Myclass> other = new MyClass<Myclass>(new Myclass());
List<int> intlist = new List<int>();
}
public class Myclass
{
public Myclass()
{
}
public int i { get; set; }
}
public class MyClass<T> where T : Myclass
{
T value;
public MyClass(T val)
{
value = val;
}
}
}
答案 3 :(得分:0)
这是一个经典的成语,奇怪的重复模板模式,用C#完成。
这意味着模板只能这样使用:
class Foo : MyClass<Foo>
{
}
在此结构中,Foo
继承了继承MyClass<Foo>
的{{1}}。
这有一些优点,但我忘记了哪一个。
答案 4 :(得分:-1)
public abstract class MyClass<TMyClass> : MyClass
where TMyClass: MyClass<TMyClass>
{
...
}
首先要指出的是,这是一个从另一个抽象类继承的抽象类。换句话说,这是一个无法实例化的类(没有从中继承的另一个类),但是使用继承来从另一个抽象类派生功能(这很好)。
要指出的第二点是,这是一个模板类(或在C#中调用它的泛型类),它接受类型。我会把它简化为T作为约定,这样T总是一个模板,尽管它完全取决于你所谓的东西。
最后对此有一个限制,这有点奇怪。它说,无论如何,编译器都不允许任何类类型作为模板类型传入,除非它继承自(继承链的某个地方)
MyClass<TMyClass>
这显示在以下行
中 where TMyClass: MyClass<TMyClass>
基本上这可以防止任何人传入不遵守此规则的对象。
有点奇怪的是,约束告诉实现者它不能是模板,除非模板传递的类型实际上是一种类型。你作为这个类(或实现者)的设计者必须决定这是否是一个明智的设计,虽然这本身看起来有点奇怪。