c#泛型自引用声明

c# generic self-referencing declarations

我一直在读阿尔巴哈里斯的"C 5.0简而言之",我在仿制药部分遇到过这个问题,据说它是合法的:

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

这对我来说毫无意义,尽管我已经仔细阅读了整个章节。我一点也听不懂。

有人能用一些可以理解的名字解释一下吗,比如:

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

以及一个实际的应用场景,在这个场景中,这种用法是适当的和有用的?


这意味着T必须从Person继承。

这是在基类中创建特定于类型的方法、属性或参数的一种典型方法,具体到实际的子代。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

当您使用一些外部库或框架(您不能或不想修改)时,这是很有帮助的。例如,您有这个库中的类User,肯定有开发人员会使用它来定义从它继承的CustomUser类(只是为了添加一些自定义字段)。另外,让我们设想一下,User类有一些对其他用户的引用,例如:creator和delator(这显然是CustomUser类型的实例)。在这种情况下,一般的自引用声明可以很好地帮助您。我们将后代类型(CustomUser作为参数传递给基类(User类),因此在User类声明中,我们可以按照未来的类型(CustomUser来设置创建者和委托者的类型,因此不需要强制转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;}
}

用途:

1
2
3
4
5
CustomUser customUser = getUserFromSomeWhere();
//we can do this
var creatorsAge = customUser.creator.Age;
//without generic approach:
//var creatorsAge = ((CustomUser)customUser.creator).Age;