2011-12-06 54 views
4

我正在學習Nhibernate 3.0。在示例代碼的例子之一,它創建了一個抽象基實體類:需要幫助來理解這個C#泛型類

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

然後,使Customer實體從Entity基類繼承:

public class Customer : Entity<Customer> 

我知道這是一個抽象的通用類,它使用where關鍵字來確保類型TEntity<T>,這是我感到困惑的地方。從

Customer繼承 「Entity<Customer>」,這個 「Entity<Customer>」 以 「Customer」 爲T,但這Customer不是 「Entity<T>」。

請幫我理解這一點,我被這個泛型類弄糊塗了。

+0

你能否把一個鏈接到你的實際的例子,如果例子是在網絡上的某個地方?我有搜索,但我找不到它。我自己也有這個問題。乾杯。 – Greenonline

回答

8

你說

客戶從 「實體」 繼承,這個 「實體」 以 「客戶」 爲T, 但是這個客戶是不是 「實體」

不有意義的,因爲這就是繼承的含義。它確立了「是一種」關係。所以其實一 CustomerEntity

對不起這是基於與剝離出來,因爲它在一個代碼塊不是泛型的代碼。

雖然相同的原理仍然有效。這有點令人困惑,因爲它看起來像是一個遞歸定義,但事實並非如此。

把它想象爲Customer繼承自Entity恰好存在依賴於泛型參數本身的方法或字段,例如, Customer。我不熟悉NHibernate,所以我不知道Entity<T>的其餘部分是什麼樣的,但我想它有一些方法使用它自己的類型作爲通用參數。

例如說有一個叫

public IEnumerable<T> GetEntities() 

方法返回它自己的實例的列表。它需要該方法來返回具體類型而不是基類型。所以在Customer類,該方法是

public IEnumerable<Customer> GetEntities<Customer>() 

如果沒有泛型參數,它只能返回IEnumerable<Entity>

這只是一個,我不它是如何被使用的案例不知道它是如何使用的。

+0

對不起,它沒有任何意義,因爲我真的很困惑,並試圖瞭解它是如何工作的。你能糾正我說的更有意義嗎? – qinking126

+0

@feelexit你說「客戶」不是「實體」但它是。該班級被宣佈爲「公共班級客戶:實體」,這意味着「客戶」***是***實體。 – Davy8

0

where子句指定的條件是代入代替T必須服從。因此,如果類型是Customer,如在該第二行代碼中的Entity<Customer>,則條件是Customer : Entity<Customer> ......即Customer必須是Entity<Customer>的子類別,否則存在編譯錯誤。事實上,它在第二行代碼中又如此聲明。

這適用於你寫的:

這個「Entity<Customer>」以「客戶」爲T

這是我會怎麼說的:Entity<Customer>Customer用於取代Entity<T>一個實例TT只是某種類型的佔位符;這是一個類型參數

但是這位客戶是不是「Entity<T>

我們可以同樣出色SOMETYPE而不是T寫抽象方法聲明。的條件是,以實例化Entity<SOMETYPE>SOMETYPE必須Entity<SOMETYPE>的子類。用Customer代替SomeType,即Customer必須是Entity<Customer>的一個子類,它是。

如果你明白T只是一個參數,那Customer是在Entity<Customer>的情況下取代它,那麼我不明白爲什麼你說「這個客戶是不是‘Entity<T>’」,因爲Customer : Entity<Customer>聲明它只是(CustomerEntity<T>的定義中每次出現時都替換爲T)。

1

當您考慮基礎「實體」類嘗試執行的操作時,它會更有意義。我對nhibernate也不熟悉,但我會想象其中一種方法可能類似於Save()方法。因此,您創建的任何從Entity類繼承的類都將繼承Save()方法,使您不必爲每個業務對象重寫它。但是,基本實體類必須知道您要保存的對象類型。它可以使用反射,但是在這裏它使用泛型來讓你告訴它是什麼類的繼承實體。

問題是,當20個不同的類從基類繼承時,該基類並不知道誰在使用它的功能。這是一種讓基類知道「客戶」正在使用其方法的方法,以便它可以專門迎合「客戶」的需求。

0

樣品展示一個如何使用這種繼承:

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(); 
}