Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

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?

like image 741
emre Avatar asked Oct 30 '15 07:10

emre


4 Answers

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
like image 169
Lasse V. Karlsen Avatar answered Oct 07 '22 02:10

Lasse V. Karlsen


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;
like image 30
Slava Utesinov Avatar answered Oct 07 '22 02:10

Slava Utesinov


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.

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.

Imagine a framework where the crud object is based on crudBase and everything inherits from that. 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.

Making queryBase a generic is simple because its fairly obvious how you would declare it

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. 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.
(pick a number, the % numbers are not important)

The GENERIC solution is less obvious here. In the first case you GENERIC class is referencing a different class with T. In this case, you want to reference the same class with 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%.

Again, without generics, I have to copy paste my CopyMe() function in each concrete class.

like image 24
greg Avatar answered Oct 07 '22 03:10

greg


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
like image 21
Sanan Fataliyev Avatar answered Oct 07 '22 01:10

Sanan Fataliyev