2008-10-20 9 views
5

Ich habe 3 Klassen, die im Wesentlichen die gleichen sind, aber keine Schnittstelle implementieren, da sie alle aus verschiedenen Webdiensten stammen.C# Generics: Kann ich auf eine Reihe von Klassen beschränken, die keine Schnittstelle implementieren?

z.B.

  • Service1.Object1
  • Service2.Object1
  • Service3.Object1

Sie alle haben die gleichen Eigenschaften und ich einige Code schreibe sie miteinander zu kartieren ein Zwischenobjekt unter Verwendung der meine eigene Schnittstelle implementiert IObject1

ich habe dies mit Generika getan

public static T[] CreateObject1<T>(IObject1[] properties) 
    where T : class, new() 
{ 
    //Check the type is allowed 
    CheckObject1Types("CreateObject1<T>(IObject1[])", typeof(T)); 
    return CreateObjectArray<T>(properties); 
} 

private static void CheckObject1Types(string method, Type type) 
{ 
    if (type == typeof(Service1.Object1) 
    || type == typeof(Service2.Object1) 
    || type == typeof(Service3.Object1) 
    || type == typeof(Service1.Object1[]) 
    || type == typeof(Service2.Object1[]) 
    || type == typeof(Service3.Object1[])) 
    { 
    return; 
    } 

    throw new ArgumentException("Incorrect type passed to ServiceObjectFactory::" + method + ". Type:" + type.ToString()); 
} 

Mein Client-Code wie folgt aussieht:

//properties is an array of my intermediary objects 
Object1[] props = ServiceObjectFactory.CreateObject1<Object1>(properties); 

Was will ich tun ist, der CheckObject1Types Methode loszuwerden und stattdessen Einschränkungen verwenden, so dass ich einen Build-Fehler erhalten, wenn die Typen nicht gültig sind, denn bei Sobald ich diese Methode mit einem beliebigen Typ aufrufen kann, wird die ArgumentException von der CheckObject1Types-Methode ausgelöst.

So würde Ich mag, wie etwas zu tun ist:

public static T[] CreateObject1<T>(IObject1[] properties) 
    where T : class, new(), Service1.Object1|Service2.Object1|Service3.Object1 
{ 
    return CreateObjectArray<T>(properties); 
} 

Irgendwelche Ideen?

Bearbeiten: Ich möchte nicht die Reference.cs-Dateien für jeden Webservice ändern, weil alles was es braucht, ein Teamkollege ist, um die Web-Referenz und BAM zu aktualisieren! gebrochener Code.

+0

Mir ist gerade aufgefallen, dass ich die Effizienz des Prüfcode verbessern kann, indem ich ihn von && auf || ändere und! = to == bevor jemand darauf hinweist. –

Antwort

14

Angenommen, die generierten Klassen sind partiell, können Sie eine Schnittstelle erstellen und dann eine weitere partielle Quelldatei hinzufügen, damit Ihre generierten Klassen die Schnittstelle implementieren. Dann können Sie per Schnittstelle wie gewohnt einschränken. Keine Änderungen am tatsächlich generierten Code erforderlich :)

+0

Das ist irgendwie, was ich versuchte zu bekommen. –

+0

Guter Punkt über den partiellen Klassentrick. Ich habe gerade ein neues Projekt, das ich in VS2008 (.NET 3.5) erstellt habe, mit einer Service-Referenz betrachtet und den Client als Teilklasse erstellt. –

+0

Interessant ... Ich werde es versuchen. –

1

In C# ist es nicht möglich, eine "OR" -Operation zu einer Liste von Klassen durchzuführen, wie Sie es tun möchten. (In der Tat, ich bin nicht einmal sicher, dass es auch direkt in IL legal ist.)

Ihre einzige Option ist es, weiterhin die Checktypes Stil Funktionen zu verwenden. Wenn Sie den Code für die verschiedenen Webdienste besitzen, können Sie auch eine "Sentinel" -Schnittstelle implementieren und diese als Ihre Einschränkung verwenden. Ich weiß, dass Sentinel-Interfaces nicht nach den Framework Design Guidelines empfohlen werden, aber sie haben gelegentlich ihren Nutzen (dies ist einer von ihnen).

Wie Jon hervorhebt, können Sie möglicherweise Prtial-Klassen verwenden, um eine gemeinsame Schnittstelle zu implementieren. Wenn Ihr References.cs eine Klasse implementiert:

namespace TestServices 
{ 
    internal partial class Service1SoapClient : System.ServiceModel.ClientBase<T>, K 
    { 
    } 
} 

Sie würden dann eine andere partielle Klasse im gleichen Namensraum erstellen (nennen wir es References.CommonInterface.cs), die überall in Ihrem Projekt leben können, mit den folgenden:

namespace TestServices 
{ 
    internal interface ICommon 
    { 
    } 

    internal partial class Service1SoapClient : ICommonInterface 
    { 
    } 
} 
+0

Fair genug, ich hoffe, Sie haben sich jedoch als falsch erwiesen! Jede Erweiterung, warum das so ist? Ich besitze den Code nicht - ja, ich könnte durch die Reference.cs gehen und jede Klasse manuell einer gemeinsamen Schnittstelle zuweisen, aber wenn ein Teammitglied die Webreferenzen aktualisiert - BAM! Keine Schnittstelle mehr. –

+0

Siehe Jon Skeets Antwort bezüglich der Möglichkeit, partielle Klassen zu verwenden, um alles von einer gemeinsamen Schnittstelle abzuleiten. –

+0

In diesem Artikel erfahren Sie, warum eine "Einschalttyp" -Funktion nicht implementiert wurde, was wahrscheinlich viele Gründe hat. http://blogs.msdn.com/peterhal/archive/2005/07/05/435760.aspx –

-2

Wenn Sie diese Objekte aus einem Webdienst ziehen, haben Sie möglicherweise die Kontrolle über die verwendeten Klassendefinitionen. Sie entstehen nicht einfach nur aus dem Nichts (auch wenn Code-Generator oder Visual Studio sie anfangs erstellen). Es gibt immer noch eine Klassendatei für jeden von ihnen, die mit der App kompiliert werden muss, und Sie sollten Ihre gemeinsame Schnittstelle zu diesen Klassendefinitionen hinzufügen können.

+0

Siehe meinen Kommentar zu Scott Dormans Antwort. –

+0

Ist das nicht, wofür Quellcodeverwaltung ist? –

+0

Stimmt, ich mag das einfach nicht. Code riechen? –

0

Ich würde eine Konverterklasse schreiben, die eines Ihrer drei Objekte in ein neues Objekt übernommen hat, das die von Ihnen gewünschte Schnittstelle unterstützt. Außerdem würde ich Reflexion verwenden, so dass Sie nicht alle Zuweisungen manuell eingeben müssen (es sei denn, es handelt sich um ein kleines Objekt, von dem nicht erwartet wird, dass es sich zu sehr ändert).

Die Verwendung von Reflection gibt Ihnen auch die Garantie, dass Sie sicherstellen möchten, dass die Objekte alle Eigenschaften implementieren, die Ihr neues Interface-Objekt implementiert. Anderenfalls könnten Sie einen Fehler auslösen, wenn eine erwartete Eigenschaft nicht implementiert ist.

Verwandte Themen