2012-10-10 71 views
5

我有基類,我的實體創建泛型列表

public class Entity<T> where T : Entity<T>, new() 
{ 
    public XElement ToXElement() 
    { 
    } 
    public static T FromXElement(XElement x) 
    { 
    } 
} 

我都用這個奇怪的建築Entity<T> where T : Entity<T>,因爲我想靜態方法FromXElement被強類型 另外,我有一些實體,如這

public class Category : Entity<Category> 
{ 
} 
public class Collection : Entity<Collection> 
{ 
} 

如何創建我的實體的泛型列表,使用基類?

var list = new List<Entity<?>>(); 
list.Add(new Category()); 
list.Add(new Collection()); 
+0

你想完成什麼?爲什麼你需要一個集合中的不同類型? –

+0

而類別和集合是...自身的通用類型? –

+1

@DanielPersson它被稱爲[好奇重複的模板模式](http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx) –

回答

4

你不能用那個定義。在CategoryCollection(當然不包括object)之間沒有「共同基類」。

如果有,說,如果Entity<T>定義爲:

public class Entity 
{ 
} 

public class Entity<T> : Entity where T : Entity<T>, new() 
{ 
    public XElement ToXElement() 
    { 
    } 
    public static T FromXElement(XElement x) 
    { 
    } 
} 

那麼你可以做

var list = new List<Entity>(); 
list.Add(new Category()); 
list.Add(new Collection()); 

但是你會說你買?

+0

我需要基類中的FromXElement/ToXElement。這不適合 – Evgraf

+0

@Evgraf - 那麼你必須投。沒有'Category'和'Collection'都實現的'FromXElement'方法(因爲它們具有不同的返回類型)。 –

0

可以定義非通用類是基類的所有實體類

public class Entity 
{ 
} 

,讓實體繼承實體

public class Entity<T> : Entity where T : Entity<T>, new() 
{ 
} 

現在你可以創建實體的列表作爲:

var list = new List<Entity>(); 
0

你可以解決這個p通過添加類的非通用版本roblem

class Entity 
{ 
    // methods 

    public T As<T>() 
    { 
    if (this is T) return (T)this; 
    throw new InvalidCastException(); 
    } 
} 

class Entity<T> : Entity where T : Entity<T>, new() 

class Cathegory : Entity<T> {} 

,然後創建基類的列表:

var list = new List<Entity>() 
list.Add(new Cathegory()); 

然後,如果你要調用一個「通用的具體」操作,需要調用「As」函數或簡單地投射對象。

1

創建一個標記接口:

public interface IAmAGenericEntity { } 

public class Entity<T> where T : IAmAGenericEntity, new() 
// ... 

public class Category : Entity<T>, IAmAGenericEntity 
// .... 

var list = new List<IAmAGenericEntity>(); 
// ... 
1

由於缺乏有關Entityabstract標記,我認爲To/FromXElement使用反射,並應爲Entity任何亞型工作。我建議你組織你的類如下:

public class Entity 
{ 
    public XElement ToXElement() { ... } 

    protected static T FromXElement<T>(XElement x) 
     where T : Entity 
    { 
     ... 
    } 
} 

public class Category : Entity 
{ 
    public static Category : FromXElement(XElement x) 
    { 
     return FromXElement<Category>(x); 
    } 
} 

的「樣板」是最小的,它並不需要你創造性地規避類型系統。您不必擔心缺乏共同基礎或手動轉換。如果你喜歡,你可以完全消除的樣板,只是直接從Entity構建你的對象:

public class Entity 
{ 
    public XElement ToXElement() { ... } 

    public static T FromXElement<T>(XElement x) 
     where T : Entity 
    { 
     ... 
    } 
} 

從本質上說,你在做什麼正在實施一種類,C#不直接支持。有很多方法可以解決這個問題,但我通常會發現它們比它們的價值更麻煩,特別是當涉及到靜態方法時。如果C#支持靜態擴展方法,它會很簡單,但是它不會。