Что делает эта конструкция C# и почему? Класса MyClass: MyClass в котором
я наткнулся на следующий код, все в одном файле/классе. Я опускаю детали, это конструкция, которая меня интересует. Почему существуют два разных объявления для одного и того же класса и как они отличаются? Какова цель синтаксиса для второго объявления?
public abstract class MyClass
{
...
}
public abstract class MyClass<TMyClass> : MyClass
where TMyClass: MyClass<TMyClass>
{
...
}
5 ответов
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;
}
}
}
MyClass
- абстрактный класс с именем MyClass.
MyClass<TMyClass> : MyClass
- абстрактный универсальный класс с именем MyClass<>
но с общим типом с именем TMyClass
.
если вы переименуете типы, будет легче увидеть:
public abstract class MyBaseClass
{
...
}
public abstract class MyClass<T> : MyBaseClass
where T: MyClass<T>
{
...
}
типы с различной универсальной аритностью (т. е. количество параметров универсального типа, которые могут быть равны нулю или более) считаются полностью не связанными языком и могут иметь одно и то же имя.
это означает, что вы можете иметь классы Foo
, Foo<T>
и Foo<T,U>
в то же время; синтаксис позволит компилятору определить, что вы имеете в виду. Вы можете видеть, что это происходит в базовой структуре, которая включает Action
, Action<T>
так далее.
" рекурсивная " конструкция class C<T> where T: C<T>
(наследование от неродового C
ничего не меняет, поэтому я удалил его) - это C# на том, что называется Любопытно Повторяющийся Шаблон Шаблон (CRTP) в C++. Эрик Липперт!--18-->затронул эту тему очень хорошо в блоге, где вывод заключается в том, что нужно подумать более двух раз, прежде чем реализовать это-есть проблемы, которые он может решить, но решение также имеет цену.
это классическая идиома, любопытно повторяющийся шаблон шаблона, выполненный на C#.
это означает, что шаблон может использоваться только таким образом:
class Foo : MyClass<Foo>
{
}
в этой конструкции Foo
наследует MyClass<Foo>
, который наследует MyClass
.
у этого есть несколько преимуществ, но я забыл, какие.
public abstract class MyClass<TMyClass> : MyClass
where TMyClass: MyClass<TMyClass>
{
...
}
Первое, что нужно отметить, это то, что это абстрактный класс, который наследуется от другого абстрактного класса. Другими словами, это класс, который не может быть создан (без наследования от него другого класса), но использует наследование для получения функциональности от другого абстрактного класса (что нормально).
второе, что нужно отметить, это то, что это класс шаблона (или общий класс, как они называют его в C#), который принимает тип в нем . Я бы уменьшил это для T как соглашение, так что T всегда является шаблоном, хотя это полностью зависит от вас, что вы называете вещами.
наконец, есть ограничение на это, что является странным. В нем говорится, что, несмотря ни на что, компилятор не позволит передавать какой-либо тип класса в качестве типа шаблона, если он не наследует (где-то по цепочке наследования)
MyClass<TMyClass>
Это показано в следующей строке
where TMyClass: MyClass<TMyClass>
в основном это запрещает передача объекта, который не следует этому правилу.
что немного странно, так это то, что ограничения говорят исполнителю, что он не может быть шаблоном, если тип, переданный шаблоном, на самом деле не является типом самого себя. Вы, как дизайнер этого класса (или разработчик), должны решить, является ли это разумным дизайном, хотя это само по себе выглядит немного странно.