Need help to understand this common C # class

I am learning Nhibernate 3.0. In one example code example, he creates an abstract class of base entities:

public abstract class Entity<T> where T : Entity<T> 

then the Customer object is inherited from the Entity base class:

 public class Customer : Entity<Customer> 

I understand this is an abstract generic class, and it uses the where keyword to make sure that type T is equal to Entity<T> , which is where I got confused.

Customer inherits from " Entity<Customer> ", this " Entity<Customer> " accepts " Customer " as T , but this Customer not " Entity<T> ".

Please help me figure this out, I'm really confused by this general class.

+4
source share
4 answers

you said

the client inherits from "Entity", this "Entity" accepts "Customer" as T, but this client is not an "entity"

This makes no sense because it is what inherits. He establishes an "eat" relationship. So in fact Customer is Entity

Sorry this was based on code in which generics were allocated, because it was not in the code block.

The same principle is still valid. This is a bit confusing because it looks like a recursive definition, but it is not.

Think about it as Customer inherits from Entity . As it happens, there are methods or fields that depend on the most common parameter, for example. Customer . I am not familiar with NHibernate, so I don’t know what the rest of Entity<T> looks like, but I suppose it has some methods that use its own type as a general parameter.

Say for example, it has a method called

 public IEnumerable<T> GetEntities() 

which returned a list of its own instances. He needs this method to return a specific type, not a base type. So in the class Customer this method will be

 public IEnumerable<Customer> GetEntities<Customer>() 

If it did not have a common parameter, it could return an IEnumerable<Entity>

This is just an example of how it can be used, I don’t know how it was really used.

+8
source

This will make more sense if you consider what operations the Entity base class performs. I am also not familiar with nhibernate, but I would suggest that one of the methods may be something like the Save () method. This way, any class that you create that inherits from the Entity class inherits the Save () method, not allowing you to overwrite it for every business object that you create. However, the Base class class needs to know what type of object you are trying to save. It can use reflection, but here it uses generalizations so that you can tell it which class it inherits from Entity.

The fact is that when 20 different classes are inherited from the base class, this base class really does not know who uses its functionality. This is a way to let the base class know that the “Client” is using its methods so that it can satisfy the needs of the “Client”.

+1
source

The where clause specifies a condition according to which the type substituted for T must obey. So, if the type is Customer , as in Entity<Customer> in the second line of code, then the condition Customer : Entity<Customer> ... i.e. Customer must be a subclass of Entity<Customer> , otherwise an error is compiled there. And indeed, it is so declared again in this second line of code.

Applying this to what you wrote:

this " Entity<Customer> " accepts "Client" as T

Here's how I would say: Entity<Customer> is an instance of Entity<T> with Customer replaced by T T is just a placeholder for some type; this is a type parameter.

but this client is not " Entity<T> "

We could also write an abstract method declaration using SomeType instead of T The condition is that to create an instance of Entity< SomeType > SomeType must be a subclass of Entity< SomeType > . Substituting Customer for SomeType, which says that Customer must be a subclass of Entity<Customer> , and it is.

If you understand that T is just a parameter and that Customer is replaced with it in the case of Entity<Customer> , then I don’t understand why you say that "this client is not" Entity<T> ", because Customer : Entity<Customer> declares that it is simple (with Customer being replaced with T at each occurrence in the definition of Entity<T> ).

0
source

An example showing how to use such inheritance:

 class Creatable<T> where T:Creatable<T>, new() { pulibc static T Create() { T t = new T(); // we know to call new due new() constraint t.FinishCreation(); // we know that T implements this method due Creatable<T> constraint return t; } public void SomeOtherUsefulsOperation(){}; protected virtual void FinishCreation(){}; } class Child:Creatable<Child> { public Child(){}; protected override void FinishCreation(){/*do something special for this type */};} } // somewhere else void DoSomething<T>() where T:Creatable<T> { T item = Creatable<T>.Create(); item.SomeOtherUsefulOperation(); } 
0
source

Source: https://habr.com/ru/post/1384821/


All Articles