What is this C # construct and why? MyClass <TMyClass>: MyClass, where

I came across the following code, all in one file / class. I leave the details, their design is of interest. Why are there two different declarations for the same class and how do they differ? What is the syntax purpose for the second declaration?

public abstract class MyClass { ... } public abstract class MyClass<TMyClass> : MyClass where TMyClass: MyClass<TMyClass> { ... } 
+6
source share
5 answers
 public abstract class MyClass<TMyClass> : MyClass where TMyClass: MyClass<TMyClass> { ... } 

is a class that inherits from MyClass , and it accepts a generic type that should inherit from MyClass<TMyClass>


Here is a simpler example of the same for you.

  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; } } } 
+2
source

MyClass is an abstract class called MyClass.

MyClass<TMyClass> : MyClass is an abstract generic class named MyClass<> , but with a generic type named TMyClass .

If you rename types, it will be easier to see:

 public abstract class MyBaseClass { ... } public abstract class MyClass<T> : MyBaseClass where T: MyClass<T> { ... } 
+3
source

Types with different general arities (that is, the number of type type parameters that can be zero or more) are considered completely unrelated to the language and can have the same name.

This means that you can have the classes Foo , Foo<T> and Foo<T,U> at the same time; The syntax will allow the compiler to determine what you are referring to. You can see this happening in the base structure, which includes Action , Action<T> , etc.

The "recursive" construction of class C<T> where T: C<T> (inheriting from non-generic C does not change anything, so I deleted it) is C # on what is called Curiously Repeating Pattern Template (CRTP) in C + +. Eric Lippert very well covered this topic on the blog, where the conclusion is that before implementing this, you should think more than two times - there are problems that he can solve, but the solution also has a price.

+3
source

This is the classic idiom, Curiously Recurring Template Pattern, made in C #.

This means that the template can only be used in this way:

 class Foo : MyClass<Foo> { } 

In this construct, Foo inherits MyClass<Foo> , which inherits MyClass .

This has several advantages, but I forgot that.

0
source
  public abstract class MyClass<TMyClass> : MyClass where TMyClass: MyClass<TMyClass> { ... } 

First of all, it should be noted that this is an abstract class that inherits from another abstract class. In other words, it is a class that cannot be created (without another class inheriting from it), but uses inheritance to get functionality from another abstract class (this is good).

The second thing to note is that it is a template class (or a generic class, since it calls it in C #), which takes a type in it. I would reduce this to T as a convention, so T is always a template, although it is completely up to you what you call things.

Finally, there is a restriction on this, which is strange. It says that, in spite of everything, the compiler will not allow passing the class type as a template type if it does not inherit (somewhere along the inheritance chain)

  MyClass<TMyClass> 

This is shown on the next line.

  where TMyClass: MyClass<TMyClass> 

this basically does not allow anyone to walk in an object that does not comply with this rule.

What is a little strange is that the restrictions tell the developer that it cannot be a template if the type passed by the template is not actually a type of itself. You, as the developer of this class (or developer), must decide if this is a wise design, although this in itself looks a little strange.

-1
source

Source: https://habr.com/ru/post/955674/


All Articles