简体   繁体   English

c#通用自引用声明

[英]c# generic self-referencing declarations

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:我一直在阅读 Albaharis 的“C# 5.0 in A Nutshell”,我在泛型部分遇到过这个,据说它是合法的:

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> .这意味着T必须继承自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).例如,您有来自这个库的User类,并且肯定会使用它的开发人员将定义继承自它的CustomUser类(仅用于添加一些自定义字段)。 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).还让我们想象一下,该User类对其他用户有一些引用,例如:creator 和 deletor(这显然是CustomUser类型的实例)。 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:我们将后代( CustomUser )的类型作为参数传递给基( User )类,因此在User类声明中,我们可以完全按照将来( 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;}
}

Usage:用法:

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

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

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.当您有一系列要编写的类并且您意识到 80%(选择一个数字)的代码基本相同,除了它因 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.上面的特定模式很重要/必要,因为您希望T成为您尝试编写的类。

Imagine a framework where the crud object is based on crudBase and everything inherits from that.想象一个框架,其中 crud 对象基于 crudBase 并且所有内容都继承自该框架。 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.进一步想象一下,您有一个基类可以帮助您查询这些对象 (queryBase),并且 crudBase 和 queryBase 类将是 1:1。

Making queryBase a generic is simple because its fairly obvious how you would declare it使 queryBase 成为泛型很简单,因为它很明显你将如何声明它

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.不太明显的是如何使用 crudBase 实现相同级别的 GENERIC 必杀技。 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.假设您有 70% 的样板 CRUD 代码已经在子类中,但是还有另外 10% 的逻辑需要引用类型。
(pick a number, the % numbers are not important) (选择一个数字,% 数字并不重要)

The GENERIC solution is less obvious here. GENERIC 解决方案在这里不太明显。 In the first case you GENERIC class is referencing a different class with T .在第一种情况下,您 GENERIC 类使用T引用不同的类。 In this case, you want to reference the same class with T .在这种情况下,您希望使用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%.在这里,您将基类重新定义为泛型,您将能够捕获最后 10%。

Again, without generics, I have to copy paste my CopyMe() function in each concrete class.同样,没有泛型,我必须在每个具体类中复制粘贴我的 CopyMe() 函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C#中的自引用泛型继承 - self-referencing generic inheritance in c# 防止自引用表在C#中变成圆形 - Prevent a self-referencing table from becoming circular in c# 在ac#应用程序中显示自引用表的数据 - Displaying self-referencing table's data in a c# application 事件侦听器委托中的自引用 (C#) - Self-Referencing in Event Listener Delegates (C#) 具有自引用类型约束的通用 class - Generic class with self-referencing type constraint 强制转换自引用实体,检测泛型 - Casting of self-referencing entities, detect generic type 如何获得自引用 C# 实体以使用 JSON.Net 序列化子级? - How to get self-referencing C# Entities to serialize children with JSON.Net? 自引用对象的有序树的设计模式(C#/ ASP.Net Core / EFCore) - Design pattern for self-referencing ordered tree of objects (C#/ASP.Net Core/EFCore) C# 和实体框架 - 优化具有不定家谱的自引用实体的数据库查询 - C# & Entity Framework - optimizing DB query for self-referencing entity with indefinite family tree c# - 同一程序集中的自引用类或循环引用类如何成功编译 - c# - How do self-referencing classes or circular-referencing classes within same assembly compile successfully
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM