2015-07-24 3 views
7

Ich schreibe ein Programm und finde ein allgemeines Verhalten, also dachte ich, dies wäre ein geeigneter Anwendungsfall für eine abstrakte Basisklasse.Compiler gibt impliziten Konvertierungsfehler || Die Einschränkung meiner generischen Methode ist eine abstrakte generische Klasse

Dies ist eine vereinfachte Version meiner abstrakte Basisklasse:

public abstract class BehaviorClass<T> where T: IDomainObj 
    { 
     protected BehaviorClass(var x){...} 
     public abstract void Create(List<T> list, out string message); 
     public abstract void Delete(List<T> list, out string message); 
     ... 
    } 

Dies ist eine vereinfachte Version meiner Abgeleitete Klasse:

public class DbSheets : BehaviorClass<Sheet> 
    { 
     public override void Create(List<Sheet> sheets, out string message){...} 
     public override void Delete(List<Sheet> sheets, out string message){...} 
     ... 
    } 

Dies ist die generische Methode dass ich mit meinen abgeleiteten Klassen arbeiten möchte:

public void Import<DbObj>() where DbObj : BehaviorClass<IDomainObj> 
    { 
     var instance = (DbObj)Activator.CreateInstance(typeof(DbObj), DbAccessor); 

     // STEP 1: Remove existing values 
     var existingValues = instance.Read(); 
     instance.Delete(existingValues, out message); 

     // STEP 2: Create new IDomainObjects 
     var domainObjects = //LINQ Query.ToList(); 

     // STEP 3: Add new IDomainObjects to the instance 
     instance.Create(domainObjects, message); 
    } 

Bis zu diesem Punkt alles kompiliert, bis ich versuche Rufen Sie die Importmethode.

internal class Program 
    { 
     ... 
     intermediary.Import<DbSheets>(); 
     ... 
    } 

Dies ist die Fehler führt von dem Versuch, die Importmethode

vom Typ ‚namespace.DbSheets‘ kann nicht als Typ-Parameter ‚DbObj‘ in der generischen Typ oder Methode aufrufen 'intermediary.Import<DbObj>()' . Es gibt keine implizite Referenzkonvertierung von 'namespace.DbSheets' zu 'namespace.BehaviorClass<IDomainObj>'.

Zusammenfassung meines Denkprozesses: Im Grunde möchte ich eine generische Methode nur auf den Klassen von BehaviorClass, abgeleitet arbeiten, da ich sicher sie eine Reihe gemeinsamer Methoden und Eigenschaften zu teilen wissen. Resharper sagt, wenn ich die generische Einschränkung für die Import-Methode entferne, dass der Code kompiliert wird. Ich möchte diese Einschränkung lieber nicht entfernen, da diese Methode speziell auf der Tatsache beruht, dass dieses gemeinsame Verhalten existiert.

Hinweis: Ich benutze die IDomainObj Schnittstelle als eine Möglichkeit, den generischen Parameter auf eine bestimmte Gruppe von Klassen zu begrenzen. Es enthält zu diesem Zeitpunkt keine spezifische Funktionalität.

+4

Einfach gesagt, ein 'DbSheets' * ist kein * BehaviorClass '. Sie können eine 'List ' nicht in ihre' Create' Methode übergeben. Selbst ohne die Einschränkung würde Ihre Besetzung fehlschlagen. Es ist schwer zu sagen, was zu tun ist, ohne zu wissen, was Sie mit "instance" zu tun versuchen. –

+1

Seitennotiz: Ich habe eine Menge von "neuen hier/lesen Sie diesen/danke" Text aus Ihrem Beitrag entfernt, da es nicht direkt auf das Problem bezogen ist. Es ist ziemlich klar, dass Sie eine gute Menge Arbeit in die Post stecken und eine sehr klare Probe zeigen, die es zu einem guten Beitrag macht. –

+0

@JonSkeet Ich habe hinzugefügt, was ich mit dem 'instance' Objekt in der' Import' Methode machen möchte. –

Antwort

2

Es scheint mir, dass Sie zwei generische Typparameter benötigen:

public void Import<TBehavior, TDomain>() 
    where TBehavior : BehaviorClass<TDomain> 
    where TDomain : IDomainObj 
{ 
    var instance = (TBehavior) Activator.CreateInstance(typeof(TBehavior), DbAccessor); 

    // STEP 1: Remove existing values 
    var existingValues = instance.Read(); 
    instance.Delete(existingValues, out message); 

    // STEP 2: Create new IDomainObjects 
    var domainObjects = //LINQ Query.ToList(); 

    // STEP 3: Add new IDomainObjects to the instance 
    instance.Create(domainObjects, message); 
} 

Jetzt sollten Sie in der Lage zu nennen:

vor
Import<DbSheets, Sheet>(); 

Das Problem, dass ist kein DbSheets ist a BehaviorClass<IDomainObj> - Sie können zum Beispiel sheets.Create(new List<IDomainObj>()) nicht anrufen.

Es ist leicht klobig zwei Typargumente angeben zu müssen, und es gibt wahrscheinlich Möglichkeiten, es zu vermeiden, aber das ist der einfachste Ansatz, mit zu beginnen, glaube ich.

1

Da die Importfunktion erscheint das Verhalten Klasse eng gekoppelt zu werden (fast, als ob es in der Behavior Klasse gekapselt werden soll), warum dies nicht tun:

public abstract class BehaviorClass<TBehavior, TDomainObj> 
    where TBehavior : BehaviorClass<TBehavior, TDomainObj> 
    where TDomainObj : IDomainObj 
{ 
    protected BehaviorClass(var x){...} 
    public abstract void Create(List<T> list, out string message); 
    public abstract void Delete(List<T> list, out string message); 
    ... 
    public static void Import() 
    { 
    var instance = (TBehavior)Activator.CreateInstance(typeof(TBehavior), DbAccessor); // <- where did DbAccessor come from? 

    // STEP 1: Remove existing values 
    var existingValues = instance.Read(); 
    instance.Delete(existingValues, out message); 

    // STEP 2: Create new IDomainObjects 
    var domainObjects = //LINQ Query.ToList(); 

    // STEP 3: Add new IDomainObjects to the instance 
    instance.Create(domainObjects, message); 
    } 
} 

es wie folgt verwendet:

public class DbSheets : BehaviorClass<DbSheets, Sheet> 
{ 
    public override void Create(List<Sheet> sheets, out string message){...} 
    public override void Delete(List<Sheet> sheets, out string message){...} 
    ... 
} 

internal class Program 
{ 
    ... 
    DbSheets.Import(); 
    ... 
} 

Bonus:

Da Sie DbAccessor sind hartzucodieren sowieso (woher kommt dieser herkomme), gehen Sie wie folgt Activator.CreateInstance im Code zu vermeiden (es kann wird immer noch von dem zugrunde liegenden Framework verwendet, aber das ist nicht Ihr Anliegen und das Framework-Team kann es später optimieren).

public abstract class BehaviorClass<TBehavior, TDomainObj> 
    where TBehavior : BehaviorClass<TBehavior, TDomainObj>, new() 
    where TDomainObj : IDomainObj 
{ 
    protected BehaviorClass():this(DbAccessor){} // <- where did DbAccessor come from originally? 
    protected BehaviorClass(var x){...} 
    public abstract void Create(List<T> list, out string message); 
    public abstract void Delete(List<T> list, out string message); 
    ... 
    public static void Import() 
    { 
    var instance = new TBehavior(); 

    // STEP 1: Remove existing values 
    var existingValues = instance.Read(); 
    instance.Delete(existingValues, out message); 

    // STEP 2: Create new IDomainObjects 
    var domainObjects = //LINQ Query.ToList(); 

    // STEP 3: Add new IDomainObjects to the instance 
    instance.Create(domainObjects, message); 
    } 
} 
Verwandte Themen