问题
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?
回答1:
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
回答2:
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
// and runtime is happy with that
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
回答3:
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;
来源:https://stackoverflow.com/questions/33430463/c-sharp-generic-self-referencing-declarations