2012-03-30 19 views
1

Ursprünglich geschrieben, um eine Liste zu kopieren, die in einem SOAP-Namespace MyOldService zu einer Klasse desselben Layouts in einem neuen Namespace MyNewService definiert wird. Das Problem ist, dass bei Soap-Klassen, wenn ich den MyOldService-Namespace in einen dritten Namespace, sagen wir MyOtherAppService, importiere, dann wird meine AddressList-Klasse ein Mitglied dieses dritten Namespace und wird als solcher referenziert.Wie kann ich einen Namespace an eine Methode übergeben?

Also, anstatt den Code zu duplizieren, würde ich es dekorieren (oder irgendwie anpassen) mit etwas ähnlich wie Generika (die ich verstehe, wird nicht funktionieren, weil ich den Namespace, nicht nur einen behoben type [es gibt mehrere Typen, die ich von jedem Namespace benötige, wie aus dem Snippet ersichtlich ist], um es zu ermöglichen, die Adressliste in die entsprechende Klasse in dem Namespace zu konvertieren, der benötigt wird. Möglich?

Bearbeiten: Als Antwort auf einige der folgenden Kommentare, werde ich versuchen, ein besseres Beispiel zu definieren, was ich versuche zu tun.

Drei Klassen importiert von WSDLs über Web-Referenzen (nein, diese werden nicht kompiliert, nur Beispiele zur Veranschaulichung). Die Klassen AddressList haben alle das gleiche Layout.

namespace A 
{  
    enum Mode {}; 
    enum Creator {}; 

    class ATypeClass {} 

    public partial class AddressList 
    { 
     int id; 
     enum Mode mode; 
     enum Creator creator 
     long[] siteList; 
     ATypeClass[] cspList; 
    } 
} 

namespace B 
{  
    enum Mode {}; 
    enum Creator {}; 

    class BTypeClass {} 

    public partial class AddressList 
    { 
     int id; 
     enum Mode mode; 
     enum Creator creator 
     long[] siteList; 
     BTypeClass[] cspList; 
    } 
} 

namespace C 
{  
    enum Mode {}; 
    enum Creator {}; 

    class CTypeClass {} 

    public partial class AddressList 
    { 
     int id; 
     string name; 
     enum Mode mode; 
     enum Creator creator 
     long[] siteList; 
     CTypeClass[] cspList; 
    } 
} 

Ich werde die partielle Klasse im Namensraum A mit einer neuen Methode erweitern:

namespace A 
{ 
    public partial class AddressList 
    { 
     public T.AddressList ToPrivateAddressList<T>() 
     { 
      T.AddressList privAddrList = new T.AddressList(); 

      privAddrList.creator = (T.Creator)this.creator; 
      privAddrList.id = this.id; 
      privAddrList.name = this.name; 
      privAddrList.mode = (T.Mode)this.mode; 

      if (this.siteList != null && this.listType == Mode.XDAddressingModeSiteIDList) 
      { 
       privAddrList.siteList = new long[this.siteList.Length]; 
       Array.Copy(this.siteList, privAddrList.siteList, this.siteList.Length); 
      } 
      ... 
     } 
    } 
} 

Beachten Sie, dass ein Teil des Problems, zusätzlich zu den Klassen jeweils Teil eines anderen Namespace, sind die Enums, die auch aus den verschiedenen Namespaces stammen.

Schließlich Ich sehe es wie so nennen (obwohl ich weiß, ich kann das nicht wirklich tun, ich bin für eine Lösung, die etwa so elegant ist):

B.AddressList al1 = A.AddressList.ToPrivateAddressList<B>(); 
C.AddressList al1 = A.AddressList.ToPrivateAddressList<C>(); 
+3

Wo ist das Problem mit Referenzierung? Sie können immer auf eine Klasse mit ihrem vollständigen Namen (namespacename.classname) verweisen, oder? – Vlad

+0

Ich denke, er will in der Lage sein, die Adresse Klasse ohne eine FQN – payo

+0

@payo zu reflecting: Ich glaube nicht, dass diese Bequemlichkeit extra Code wert ist :) – Vlad

Antwort

0

Ich denke, was Sie suchen, ist eine Schnittstelle und das Schlüsselwort where in der generischen Typdefinition.

Von Ihrem Code sehe ich, dass Sie diese haben:

  • eine Methode, die A konvertiert Typ B
  • geben Sie es dies nicht von Eigenschaften mit dem gleichen Namen
  • und dann gibt die neue Zuordnung Typ B
  • die Typen können in unterschiedlichen Namensräumen befinden (aber zur Zeit haben den gleichen Namen)
  • Klassen sind partial

Anstatt sich auf den gleichen Namen zu verlassen (was Sie können, können Sie mit Reflexion den gewünschten Effekt erzielen), sollten Sie jede Klasse eine Schnittstelle implementieren lassen, die die allgemeinen Eigenschaften enthält. Auf diese Weise behalten Sie Zeit Typsicherheit kompilieren:

public interface ICommonAddress 
{ 
    int id { get; set; } 
    Mode mode { get; set; } 
    Creator creator { get; set; } 
    long[] siteList { get; set; } 
    ICommonAddress CreateAddress(); 
} 

Sie können nun Ihre Klassen wie diese Refactoring (natürlich werden Sie Ihre Felder in Eigenschaften ändern müssen, aber ich nehme an, Sie haben sie als bereits Eigenschaften:.

// if your original partial class is auto-generated, it is ok to place 
// this definition in another file, it'll still work as long as 
// namespace, classname and compile-unit (must be in same project) are the same 
public partial class AddressList : ICommonAddress 
{ 
    int id { get; set; } 
    Mode mode { get; set; } 
    Creator creator { get; set; } 
    long[] siteList { get; set; } 
    ATypeClass[] cspList; 

    ICommonAddress CreateAddress() 
    { 
     return new AddressList(); // NOTE: you can even have your ctor private! 
    } 
} 

Wenn Sie tun, dass Sie für jeden Addresstyp haben, können Sie Ihre generische Methode wie folgt ändern, und es wird automatisch funktionieren, einschließlich des IntelliSense Ihnen die gemeinsame verfügbaren Eigenschaften zeigt auch, es umzusetzen als Erweiterungsmethode, so dass es für alle Adresslistentypen gilt (dies ist in Ihrem Fall besser als die Verwendung von partial) Wenn Sie einen Verweis auf diese Erweiterung Methode importieren, können Sie ToPrivateAddressList() auf jeder Art rufen

public T ToPrivateAddressList<T>(this ICommonAddress _this) 
    where T: ICommonAddress 
{ 
    T privAddrList = _this.CreateAddress(); 

    // this now works normally, without casting 
    privAddrList.creator = _this.creator; 
    privAddrList.id = _this.id; 
    privAddrList.name = _this.name; 
    privAddrList.mode = _this.mode; 
} 

Nun, die Sie haben:

A.AddressList a_address = A.AddressList.CreateAddress(); // or new A.AddressList() 
B.AddressList al1 = a_address.ToPrivateAddressList<B.AddressList>(); 
C.AddressList al1 = a_address.AddressList.ToPrivateAddressList<C.AddressList>(); 
+0

Ich denke, ich sehe, wohin du gehst, aber der eine Vorbehalt, der hier im Weg stehen könnte, ist, dass die A-, B- und C-Namespaces (jeweils mit der zugehörigen AddressList-Klasse) aus WSDL-Dateien über Web-Referenzen importiert werden. .. so werden die Felder, enums und so automatisch für mich beim Import definiert. Ich habe die Klassen in einer gSOAP-Definitionsdatei definiert, die WSDL erstellt und dann in die aktuelle Anwendung importiert. Nun, ich nehme an, ich könnte einen einmaligen Import machen und dann die Dateien ändern, die für mich generiert werden, aber wir möchten den automatisch generierten Code nicht verändern. – Jon

+0

@ Jon: das ist in Ordnung. Aus diesem Grund enthalten automatisch generierte Klassen in der Regel "partielle" Klassendefinitionen. Wenn Sie Ihre Frage berücksichtigen, glaube ich, dass dies auch Ihre ist. Auch wenn eine partielle Definition nicht und eine andere nicht ': ICommonAddress' enthält, spielt es keine Rolle, solange die kombinierte Klasse eine Implementierung der Schnittstelle enthält. Legen Sie sie in eine separate Datei und Sie können Ihre automatisch generierten Klassen unverändert lassen. (EDIT: Ich habe die Antwort bearbeitet, um dies zu reflektieren). – Abel

+0

Das sieht ziemlich interessant aus! Ich werde über Erweiterungsmethoden nachlesen müssen, da ich mich nie zuvor mit ihnen beschäftigt habe, daher kenne ich die Methodensignatur, die Sie geschrieben haben, nicht. Wird morgen weiter forschen! – Jon

0

Wenn ich Recht Problem undesrtood Sie

namespace A 
{ 
    public class MyClass {... } 
} 

und

namepsace B 
{ 
    public class MyClass {...} 
} 

Ihre Frage ist haben: wie kann ich etwas "generic" tha definieren t in der gleichen Funktion behandelt manchmal A.MyClass und andere Fälle B.MyClass.

Wenn Sie Namespaces wie Teil der Typdefinition denken, denke ich, die Geschichte wird klar. Wie wenn Sie 2 verschiedene Typen haben und ein generisches haben möchten, das mit beiden arbeitet. Diese generische Klasse kennt, wenn A.MyClass Methode zu wählen, und wann B.MyClass Methode wählen.

Wenn es nicht das ist, was Sie verlangen, bitte klären.

+0

Siehe meinen ersten Post, ich habe geklärt, was ich tun möchte. – Jon

0

Sind Sie fragen, wie Sie dies tun können: ‚Neue‘

namespace Old 
{ 
    public New.Address Foo() 
    { 
    New.Address result; 
    //... 
    return result; 
    } 
} 

Ohne sagen zu müssen bei jedem Auftreten von Adresse? Aber wenn nicht, verwendet der Code Old.Address?

Können Sie Old.Address aus dem Build/Linking dieses Projekts (mit diesem Code) entfernen?

+0

Ich habe im ersten Post einige zusätzliche Notizen gemacht. – Jon

Verwandte Themen