2009-05-04 12 views
4

Ich habe eine Klasse definiert wie folgt;C# -Syntax zum Deklarieren einer Variablen eines abstrakten generischen Typs

public abstract class Repository<TEntity, TDataContext> : DisposableBaseClass 
    where TEntity : class 
    where TDataContext : DataContext, new() 
{...contains Linq to SQL related functionality 

In der konkreten Unterklasse definiere ich die Typen als so;

Bei der nächsten Stufe nach oben habe ich Geschäftsobjekte, die das Repository-Objekt als private Variable enthalten.

Das war in Ordnung;

private ConcreteRepo _repository; 

Allerdings habe ich dann diese in eine übergeordnete Klasse für die ganze Geschäftsobjekte Refactoring - dieser übergeordneten Klasse hält die Repository/Arbeitsgeräte Muster-Repository zu entsorgen Entsorgen usw.

Mein Problem ist, dass ich nur kann die Syntax nicht richtig für die Deklaration der Variablen bekommen.

Die nächste, die ich gekommen bin, ist;

protected Repository<Object, DataContext> _repository; 

aber dies gibt den Compiler-Fehler:

„Fehler 1‚System.Data.Linq.DataContext‘muss ein nicht-abstrakter Typ mit einem öffentlichen parameterlosen Konstruktor sein, um es als Parameter zu verwenden 'TDataContext' in der generischen Art oder Methode '.... Repository' ... "

Ich habe verschiedene andere Dinge ausprobiert, aber andere Probleme getroffen.

In dem Business-Schicht-Objekt, das diese abstrakte Klasse erbt, erstelle und benutze ich die Variable _repository mit einem Cast;

(Repository<LSTableClass, LSDataContext>)_repository = new ConcreteRepo(); 
  • und ich denke, das ist in Ordnung sein wird, vorausgesetzt, ich diese Erklärung direkt im Eltern erhalten kann.

Wenn ich das nicht bekommen zu arbeiten, ich habe den _repository in jedem Business-Objekt zu erklären, mit den vollständigen/konkreten Details und implementieren in jedem das dispose Muster zu klären. Nicht das Ende der Welt, aber ich möchte es nicht müssen.

+0

Also verstehe ich richtig, dass "private ConcreteRepo _repository;" ist in der Klasse, die Sie refaktoriert haben? Sie möchten, dass die Klasse, die Sie schreiben, dieses Repository-Feld enthält * UND * ist der TEntity-Typ-Parameter des Repositorys? Genau das, was Sie refaktorisiert haben, ist mir nicht ganz klar. –

Antwort

3

Wenn ich Ihr Problem richtig verstanden habe, müssen Sie einen dritten generischen Parameter hinzufügen, den Repository-Typ, der als Nachkomme von Repository mit den entsprechenden Argumenttypen definiert ist.

ihm etwas mehr zu skizzieren: Ich weiß, es ist wahrscheinlich nicht so kompakt wie Sie mögen,

public abstract class Repository<TEntity,TDataContext> 
    where TEntity : class 
    where TDataContext : DataContext, new() {} 

public abstract class BusinessObject<TEntity,TDataContext,TRepository> 
    where TEntity : class 
    where TDataContext : DataContext, new() 
    where TRepository : Repository<TEntity,TDataContext> 
{ 
    TRepository _repository; 
} 

public class ConcreteObject : BusinessObject<LSTableClass,LSDataContext,ConcreteRepo> 
{ // ... 

aber effektiv noch was nötig zu reduzieren unten noch die starke Typisierung behalten, sind höhere Ordnung generische Typen (Typklassen in Haskell): eine Möglichkeit, anzugeben, dass Typparameter selbst generisch sind und Typparameter annehmen können.

+0

Danke Barry, das ist genau das, was ich brauchte, alles funktioniert jetzt, vielen Dank – DannykPowell

3

Ihre Erklärung

protected Repository<Object, DataContext> _repository; 

wegen der Einschränkung nicht arbeiten Haben Sie an sie gestellt:

...  
where TDataContext : DataContext, new() 

Insbesondere die new() Teil.

Ich vermute, dass Sie ein Objekt "injizieren" wollen, das Ihre generische Schnittstelle erfüllt.

Zwei Dinge:

  • Sie zwischen Repository<Object, DataContext> und Repository<LSTableClass, LSDataContext> nicht konvertieren kann. Nicht mit C# 3. Dies heißt Contravariance/Covariance und wird nicht verfügbar sein, bis C# 4. In C# 3 sind dies zwei völlig verschiedene Arten.

  • Wenn Sie ein generisches Element, das innerhalb einer Klasse speichern wollen, dann ist entweder die Typargumente konkrete Typen sein müssen, oder sie müssen als Typ-Parameter in der übergeordneten Klassendeklaration deklariert werden (was dass Generika).

Optionen:

  • Verwendung generischer Typ Argumente auf Ihrer Elternklasse.
  • Entfernen Sie die new() - Einschränkung aus Ihrer Klassendeklaration.
+0

Danke für die Antwort Matt; Leider scheint es, als könnte ich nur eine Antwort als die richtige Antwort markieren, sonst würde ich auch deine markieren. Ich ging mit der ersten Option, wie Sie sie setzen, wie Sie richtig in Ihrer Annahme waren, dass ich ein Objekt injizieren muss, so dass die neue() Einschränkung beibehalten werden muss. Danke nochmal für die Antwort – DannykPowell

Verwandte Themen