我一直在读Albaharis' " C#5.0 in A Nutshell"我在Generics部分遇到过这个问题,据说这是合法的:
class Bar<T> where T : Bar<T> { ... }
虽然我仔细阅读了整章,但这对我来说毫无意义。我甚至无法理解它。
有人可以用一些可以理解的命名解释它,例如:
class Person<T> where T : Person<T> { ... }
这个用法适用且有用的真实应用场景?
答案 0 :(得分:10)
这意味着T
必须从Person<T>
继承。
这是在基类中创建特定于类型的方法或属性或参数的典型方法,特定于实际的后代。
例如:
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
答案 1 :(得分:1)
当您要编写一系列类并且意识到80%(选择一个数字)代码本质上是相同的(除了它因类型而异)时,这也很有用。
编写通用代码可让您捕获基类中所有重复的代码,然后重复使用。
上面的特定模式是重要/必要的,因为您希望 T 成为您要编写的类。
想象一下一个框架,其中crud对象基于crudBase,并且一切都继承自该对象。 进一步想象一下,您有一个可帮助您查询那些对象的基类(queryBase),而crudBase和queryBase类的比例为1:1。
使queryBase为泛型很简单,因为它非常明显地声明了它
public abstract class queryBase<T> where T : crudBase
{
public list<T> FindMatches(string SearchCriteria){}
}
没有泛型,这将必须在每个具体的类中,因为返回类型会更改。泛型很棒。
不太明显的是如何使用crudBase实现相同水平的GENERIC必杀技。
假设您的子类中已经有70%的样板代码CRUD,但是还有10%的逻辑需要引用该类型。
(选择一个数字,百分比数字并不重要)
GENERIC解决方案在这里不太明显。在第一种情况下,您的GENERIC类使用 T 引用了另一个类。在这种情况下,您想使用 T 引用相同的类。
使用上述模式,您实际上可以实现:
public class crudBaseGeneric<T> where T : crudBaseGeneric<T>
{
public <T> CopyMe(){}
}
在这里,您将基类重新定义为泛型,并且将能够捕获到最后10%的数据。
同样,没有泛型,我必须在每个具体的类中复制粘贴我的CopyMe()函数。
答案 2 :(得分:0)
当您使用某些外部库或框架(您不能或不想修改)时,它会很有帮助。例如,您从此库中获得了类User
,并且肯定将使用它的开发人员将定义从其继承的CustomUser
类(仅用于添加一些自定义字段)。还可以想象一下,User
类对其他用户有一些引用,例如:creator和deletor(显然是CustomUser
类型的实例)。在这种情况下,通用的自引用声明可以提供很好的帮助。我们将后代的类型(CustomUser
)作为参数传递给base(User
)类,因此在User
类声明中我们可以设置创建者类型和deletor 完全因为它们将来(CustomUser
),所以不需要投射:
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;}
}
<强>用法:强>
CustomUser customUser = getUserFromSomeWhere();
//we can do this
var creatorsAge = customUser.creator.Age;
//without generic approach:
//var creatorsAge = ((CustomUser)customUser.creator).Age;
答案 3 :(得分:0)
我参加聚会可能有点晚了,但我想分享一个不真实的应用场景,以获取乐趣:)
// 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