Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should one use self-referencing generic inheritance like Customer : Entity<Customer>

Is it advisable to use self-referencing generic inheritance?

public abstract class Entity<T> {
    public Guid Id {get; set;}
    public int Version {get; set;}

    public T Clone() {
        ...
        // clone routine
        ...
        return T;
    }
}

public class Customer : Entity<Customer> {
    public string CustomerName {get; set;}
    ...
}

How does one cast Customer to the base Entity class? What advantage does "Customer : Entity" provide? I see this kind of inheritance in examples showing NHibernate domain modeling.

Is it better to use "Customer : Entity" without the generics?

like image 541
Mank Avatar asked Mar 01 '23 12:03

Mank


2 Answers

You should use it when you need it, not just because you can. In the example above, it makes some sense to implement Clone(). However, as you rightly point out, it means that your entity classes won't actually have a common base class, and properties that are truly common to them won't be accessible. The correct way to handle this is to split it in generic and non-generic parts:

public abstract class Entity {
    public Guid Id {get; set;}
    public int Version {get; set;}
}

public abstract class Entity<T> : Entity where T : Entity<T> {
    public T Clone() {
        ...
        // clone routine
        ...
        return T;
    }
}

Also, note the where part that I've added to declaration of Entity<T> - it ensures that this class can only be used as a part of this recursive pattern.

like image 109
Pavel Minaev Avatar answered Apr 06 '23 19:04

Pavel Minaev


In the company i work for, the project I work on uses heavily this kind of trick. In fact, it is even promoted as a pattern in the code. Thus i can speak from experience: don't use it.

They may be cases where the self-referencing implementation is far simpler, more efficient and easier to read, but I have never encountered such a case. Heavy use of it makes code maintenance a nightmare, and in most cases can be avoided with only a normal inheritance and a casting of your method result if needed. And the performance cost of a casting into the derived class is negligible compared to the maintenance cost of your code.

So if you find the rare example where it is advisable to use self-referencing generic inheritance, go ahead and do so. But think twice beforehand, as there is probably a better way to do it.

like image 36
Falanwe Avatar answered Apr 06 '23 17:04

Falanwe