I've been reading Albaharis' "C# 5.0 in A Nutshell" and I've encountered this in Generics section and it is said to be legal:
class Bar<T> where T : Bar<T> { ... }
And it meant nothing to me, although I've read the whole chapter carefully. I couldn't understand even a bit of it.
Can someone please explain it with some understandable naming, like:
class Person<T> where T : Person<T> { ... }
And a real-world application scenario where this usage is appropriate and useful?
It means that T
must inherit from Person<T>
.
This is a typical way to create type-specific methods or properties or parameters in the base class, specific to the actual descendant.
For instance:
public abstract class Base<T> where T : Base<T>, new()
{
public static T Create()
{
var instance = new T();
instance.Configure(42);
return instance;
}
protected abstract void Configure(int value);
}
public class Actual : Base<Actual>
{
protected override void Configure(int value) { ... }
}
...
Actual a = Actual.Create(); // Create is defined in Base, but returns Actual
It is helpful, when you work with some external library or framework(which you can't or don't want modify). For example, you have class User
from this library and definitely developer, who will use it, will define CustomUser
class, which is inherited from it (just for adding some custom fields). Also let's imagine, that User
class has some references to another users, for example: creator and deletor (which obviously will be instances of CustomUser
type). And at this case generic self-referencing declaration can help very well. We will pass type of descendant(CustomUser
) as parameter to base(User
) class, so at User
class declaration we can set types of creator and deletor exactly as they will be at future(CustomUser
), so no casting will be needed:
public class User<TCustomUser> where TCustomUser : User<TCustomUser>
{
public TCustomUser creator {get;set;}
public TCustomUser deletor {get;set;}
//not convenient variant, without generic approach
//public User creator {get;set;}
//public User deletor {get;set;}
}
public class CustomUser : User<CustomUser>
{
//custom fields:
public string City {get;set;}
public int Age {get;set;}
}
Usage:
CustomUser customUser = getUserFromSomeWhere();
//we can do this
var creatorsAge = customUser.creator.Age;
//without generic approach:
//var creatorsAge = ((CustomUser)customUser.creator).Age;
It is also helpful when you have a series of classes to write and you realize that 80% (pick a number) of the code is essentially the same except it varies by TYPE.
Writing a generic allows you to capture all that repetitive code in a base class and reuse it.
The specific pattern above is important/necessary because you want the T to be the class you are trying to write.
Imagine a framework where the crud object is based on crudBase and everything inherits from that. Imagine further that you have a base class that helps you query those objects (queryBase) and there will be a 1:1 with crudBase and queryBase classes.
Making queryBase a generic is simple because its fairly obvious how you would declare it
public abstract class queryBase<T> where T : crudBase
{
public list<T> FindMatches(string SearchCriteria){}
}
Without a generic, this would have to be in each concrete class because the return type changes. Generics are awesome.
what is a little less obvious is how to accomplish that same level of GENERIC nirvana with crudBase.
Assume you have 70% of the boiler plate CRUD code already in a subclass, but there is another 10% where the logic needs to reference the type.
(pick a number, the % numbers are not important)
The GENERIC solution is less obvious here. In the first case you GENERIC class is referencing a different class with T. In this case, you want to reference the same class with T.
using the pattern described above you can in fact achieve this :
public class crudBaseGeneric<T> where T : crudBaseGeneric<T>
{
public <T> CopyMe(){}
}
Here you will redefine your base class as a generic and you will be able to capture that last 10%.
Again, without generics, I have to copy paste my CopyMe() function in each concrete class.
I might be a little late to the party but I want to share an unreal-world application scenario for fun :)
// self referencing list in c#
// we cant use generic type syntax: new List<List<List..
// but dynamic keyword comes to save us
var list = new List<dynamic>();
list.Add(list); // the "FBI! open up" part
Console.WriteLine(list[0][0][0][0][0][0][0].Count); // 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With