I have written an extension method in csharp for an MVCContrib Html helper and was surprised at the form of the generic constraint, which on the face of it seems to circular
The reason constraint is there is because TextInput type itself has such a constraint like so.
public abstract class TextInput where T: TextInput{
//...
}
Also note that TextInput is abstract and the only way to make an instance of such class is to derive from it in a CRTP-like fashion:
public class FileUpload : TextInput {
}
The extension method will not compile without that constraint, that's why it's there.
The reason for having CRTP in the first place is to enable strongly typed methods enabling Fluent Interface on the base class, so consider such example:
public abstract class TextInput where T: TextInput{
public T Length(int length) {
Attr(length);
return (T)this;
}
}
public class FileUpload : TextInput {
FileUpload FileName(string fileName) {
Attr(fileName);
return this;
}
}
So when you have a FileUpload instance, Length returns an instance of FileUpload, even though it's defined on the base class. This makes the following syntax possible:
FileUpload upload = new FileUpload();
upload //FileUpload instance
.Length(5) //FileUpload instance, defined on TextInput
.FileName("filename.txt"); //FileUpload instance, defined on FileUpload
EDIT To address OP's comments about recursive class inheritance. This is a well known pattern in C++ called Curiously Recurring Template Pattern. Have a read of it here. Up until today I didn't know it was possible in C#. I suspect that constraint has something to do with enabling the use of this pattern in C#.