2012-10-10 14 views
5

Ich habe Basisklasse für meine EntitätenListe von Generika

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

Ich habe zu verwenden, diese seltsame Konstruktion Entity<T> where T : Entity<T>, weil ich statische Methode FromXElement will stark typisierte werden Auch ich habe einige Einheiten, wie dass

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

Wie kann ich eine generische Liste meiner Entitäten erstellen, Basisklasse verwenden?

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

Was möchten Sie erreichen? Warum brauchen Sie diese unterschiedlichen Typen in einer Sammlung? –

+0

Und Klassen Kategorie und Sammlung sind generische Arten von ... sich selbst? –

+1

@DanielPersson es heißt die [merkwürdig wiederholende Vorlage Muster] (http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiousser-and-curious.aspx) –

Antwort

4

Sie können nicht mit dieser Definition. Es gibt keine "gemeinsame Basisklasse" zwischen Category und Collection (natürlich anders als object).

Wenn es waren, sagen, wenn Entity<T> wurden wie folgt definiert:

public class Entity 
{ 
} 

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

dann könnte man

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

Aber was würden Sie das kaufen?

+0

Ich brauche FromXElement/ToXElement in der Basisklasse. Das passt nicht – Evgraf

+0

@Evgraf - dann müssen Sie werfen. Es gibt keine 'FromXElement'-Methode, die sowohl' Category' als auch 'Collection' implementieren (da sie unterschiedliche Rückgabetypen haben). –

0

Sie können eine nicht-generische Klasse definieren die Basisklasse aller Entitätsklassen sein

public class Entity 
{ 
} 

und machen Entity Entity erben

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

Jetzt können Sie die Liste der Entitäten erstellen, wie :

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

Sie können diese p lösen roblem durch eine nicht-generische Version der Klasse

Hinzufügen
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> {} 

und erstellen Sie dann die Liste der Basisklasse:

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

Dann, wenn Sie eine „generic spezifischen“ Operation aufrufen möchten, können Sie muss die "As" -Funktion aufrufen oder das Objekt einfach werfen.

1

eine Markierungsschnittstelle erstellen:

public interface IAmAGenericEntity { } 

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

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

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

Aus dem Fehlen eines abstract Marker auf Entity, gehe ich davon aus, dass To/FromXElement Verwendung Reflexion und für jeden Subtyp des Entity funktionieren sollte. Ich empfehle Ihnen, Ihre Klassen zu strukturieren wie folgt:

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

Die „vorformulierten“ ist minimal, und es ist nicht erforderlich, dass Sie kreativ die Art System umgehen. Sie müssen sich keine Gedanken über das Fehlen einer gemeinsamen Basis oder über manuelle Konvertierungen machen.Wenn Sie möchten, können Sie den Textvorschlag vollständig beseitigen und bauen nur Ihre Objekte direkt aus Entity:

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

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

Im Wesentlichen, was Sie tun, ist eine Typklasse Implementierung, die C# nicht direkt unterstützt. Es gibt eine Reihe von Möglichkeiten, um diesen Mangel zu umgehen, aber normalerweise finde ich, dass sie mehr Probleme bereiten als sie wert sind, besonders wenn es um statische Methoden geht. Wenn C# statische Erweiterungsmethoden unterstützt, wäre das einfach, aber leider nicht.