c#泛型自引用声明

时间:2015-10-30 07:05:28

标签: c# self-reference

我一直在读Albaharis' " C#5.0 in A Nutshell"我在Generics部分遇到过这个问题,据说这是合法的:

class Bar<T> where T : Bar<T> { ... }

虽然我仔细阅读了整章,但这对我来说毫无意义。我甚至无法理解它。

有人可以用一些可以理解的命名解释它,例如:

class Person<T> where T : Person<T> { ... }

这个用法适用且有用的真实应用场景?

4 个答案:

答案 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