2012-10-10 1 views
5

mam klasę bazową dla moich jednostekStwórz listę leków generycznych

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

muszę używać tę dziwną konstrukcję Entity<T> where T : Entity<T>, bo chcę metoda statyczna FromXElement być silnie wpisany Również mam kilka podmiotów, jak że

Jak utworzyć ogólną listę moich podmiotów, używając klasy bazowej?

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

Co próbujesz osiągnąć? Dlaczego potrzebujesz tych różnych typów w kolekcji? –

+0

A klasy Kategoria i kolekcja to ogólne typy ... siebie? –

+1

@DanielPersson nazywa się [ciekawie powtarzającym się szablonem wzoru] (http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx) –

Odpowiedz

4

Nie można z tą definicją. Nie ma "wspólnej klasy bazowej" między Category i Collection (inne niż object, oczywiście).

Jeśli były, powiedzieć, czy Entity<T> zostały zdefiniowane jako:

public class Entity 
{ 
} 

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

następnie można zrobić

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

Ale co by to kupić ci?

+0

Potrzebuję FromXElement/ToXElement w klasie bazowej. To nie pasuje do – Evgraf

+0

@Eggraf - wtedy będziesz musiał rzucić. Nie ma metody "FromXElement", która zarówno implementuje "Category", jak i "Collection" (ponieważ mają różne typy zwracania). –

0

Można zdefiniować nierodzajową klasę być klasą bazową wszystkich klas encji

public class Entity 
{ 
} 

i sprawiają Podmiot dziedziczyć Podmiot

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

Teraz można utworzyć listę podmiotów, :

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

Możesz rozwiązać ten problem ROBLEM dodając nierodzajową wersję klasy

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> {} 

a następnie utworzyć listę klasy bazowej:

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

Następnie, jeśli chcesz zadzwonić do „generic specyficzny” operację, ty musisz wywołać funkcję "As" lub po prostu rzucić obiekt.

1

Tworzenie interfejsu markera:

public interface IAmAGenericEntity { } 

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

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

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

Z brakiem abstract markerem na Entity zakładam, że To/FromXElement użycie odbicie i powinien działać na każdym podtypu Entity. I zaleca, aby uporządkować swoje klasy w następujący sposób:

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

The „Gotowa” jest minimalne, a to nie wymaga, by twórczo obejść system typu. Nie musisz się martwić brakiem wspólnej bazy lub ręcznych konwersji.Jeśli chcesz, możesz całkowicie wyeliminować boilerplate i po prostu skonstruować swoje przedmioty bezpośrednio od Entity:

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

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

W istocie, co robisz wdraża klasę typu, C# nie obsługuje bezpośrednio. Istnieje wiele sposobów obejścia tego problemu, ale zwykle uważam, że są one bardziej kłopotliwe, niż są warte, szczególnie jeśli chodzi o metody statyczne. Jeśli C# obsługiwane metody statycznego rozszerzenia, byłoby to proste, ale niestety nie.