wake-up-neo.net

Überschreiben Sie den Standardkonstruktor der Teilklasse mit einer anderen Teilklasse

Ich glaube nicht, dass das möglich ist, aber wenn, dann brauche ich es :)

Ich habe eine automatisch generierte Proxy-Datei aus dem Befehlszeilentool "wsdl.exe" von Visual Studio 2008.

Die Ausgabe des Proxy erfolgt in Teilklassen. Ich möchte den generierten Standardkonstruktor überschreiben. Ich möchte den Code lieber nicht ändern, da er automatisch generiert wird.

Ich habe versucht, eine andere Teilklasse zu erstellen und den Standardkonstruktor neu zu definieren, aber das funktioniert nicht. Ich habe dann versucht, die Überschreibung und neue Schlüsselwörter zu verwenden, aber das funktioniert nicht.

Ich weiß, dass ich von der Teilklasse erben könnte, aber das würde bedeuten, dass ich unseren gesamten Quellcode ändern muss, um auf die neue übergeordnete Klasse zu verweisen. Ich möchte das lieber nicht tun.

Irgendwelche Ideen, Umgehungen oder Hacks? 

//Auto-generated class
namespace MyNamespace {
   public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol {
      public MyWebService() {
         string myString = "auto-generated constructor";
         //other code...
      }
   }
}

//Manually created class in order to override the default constructor
namespace MyNamespace {
   public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol {
      public override MyWebService() { //this doesn't work
         string myString = "overridden constructor";
         //other code...
      }
   }
}
51
Elijah Manor

Dies ist nicht möglich. Partielle Klassen sind im Wesentlichen Teile derselben Klasse. Keine Methode kann zweimal definiert oder überschrieben werden. Dazu gehört auch der Konstruktor.

Sie können eine Methode im Konstruktor aufrufen und nur in der anderen Teildatei implementieren.

37
configurator

Ich hatte ein ähnliches Prolem, wobei mein generierter Code von einer dbml-Datei erstellt wurde (ich benutze Linq-to-SQL-Klassen).

In der generierten Klasse wird am Ende des Konstruktors ein teilweises Void mit dem Namen OnCreated () aufgerufen.

Um es kurz zu machen: Wenn Sie die wichtigen Konstruktoreigenschaften der generierten Klasse für Sie behalten möchten (was Sie wahrscheinlich tun sollten), erstellen Sie in Ihrer Teilklasse Folgendes:

partial void OnCreated()
{
    // Do the extra stuff here;
}
66
Tom Chantler

Hmmm, Ich denke, eine elegante Lösung wäre die folgende:

//* AutogenCls.cs file
//* Let say the file is auto-generated ==> it will be overridden each time when
//* auto-generation will be triggered.
//*
//* Auto-generated class, let say via xsd.exe
//*
partial class AutogenCls
{
    public AutogenCls(...)
    {
    }
}



//* AutogenCls_Cunstomization.cs file
//* The file keeps customization code completely separated from 
//* auto-generated AutogenCls.cs file.
//*
partial class AutogenCls
{
    //* The following line ensures execution at the construction time
    MyCustomization m_MyCustomizationInstance = new MyCustomization ();

    //* The following inner&private implementation class implements customization.
    class MyCustomization
    {
        MyCustomization ()
        {
            //* IMPLEMENT HERE WHATEVER YOU WANT TO EXECUTE DURING CONSTRUCTION TIME
        }
    }
}

Dieser Ansatz hat einige Nachteile (wie alles):

  1. Es ist nicht klar, wann genau der Konstruktor der inneren Klasse MyCustomization während des gesamten Konstruktionsprozesses der Klasse AutogenCls ausgeführt wird.

  2. Wenn die Implementierung der IDiposable-Schnittstelle für die MyCustomization-Klasse erforderlich ist, um die Beseitigung nicht verwalteter Ressourcen der MyCustomization-Klasse ordnungsgemäß zu behandeln, kann ich (noch) nicht wissen, wie die MyCustomization.Dispose () - Methode ausgelöst wird, ohne die AutogenCls.cs-Datei zu berühren ... (aber wie gesagt "noch" :)

Dieser Ansatz bietet jedoch eine gute Trennung vom automatisch generierten Code - die gesamte Anpassung wird in verschiedene Quellcodedateien unterteilt.

genießen :)

13
user307938

Das Problem, das das OP hat, ist, dass der Webreferenz-Proxy keine Teilmethoden generiert, mit denen Sie den Konstruktor abfangen können.

Ich bin auf das gleiche Problem gestoßen und kann nicht einfach auf WCF upgraden, da der angezeigte Web-Service dies nicht unterstützt.

Ich wollte den automatisch generierten Code nicht manuell ändern, da er reduziert wird, wenn jemand die Codegenerierung aufruft.

Ich habe das Problem aus einem anderen Blickwinkel angegangen. Ich wusste, dass meine Initialisierung vor einer Anfrage erledigt werden musste. Dies musste nicht wirklich zur Konstruktionszeit erledigt werden. Daher überschrieb ich einfach die GetWebRequest-Methode.

protected override WebRequest GetWebRequest(Uri uri)
{
    //only perform the initialization once
    if (!hasBeenInitialized)
    {
        Initialize();
    }

    return base.GetWebRequest(uri);
}

bool hasBeenInitialized = false;

private void Initialize()
{
    //do your initialization here...

    hasBeenInitialized = true;
}

Dies ist eine nette Lösung, da es nicht um das Hacken des automatisch generierten Codes geht und die exakte Verwendung des OP für die Durchführung der Initialisierungsanmeldung für einen automatisch generierten SoapHttpClientProtocol-Proxy erfolgt.

3
Doctor Jones

Tatsächlich ist dies jetzt möglich, da nun Teilmethoden hinzugefügt wurden. Hier ist das Dokument: 

http://msdn.Microsoft.com/de-de/library/wa80x488.aspx

Grundsätzlich besteht die Idee darin, dass Sie eine Methode in einer Datei deklarieren und aufrufen können, in der Sie die Teilklasse definieren, nicht aber die Methode in dieser Datei. In der anderen Datei können Sie dann die Methode definieren. Wenn Sie eine Assembly erstellen, in der die Methode nicht definiert ist, entfernt der ORM alle Aufrufe der Funktion.

Im obigen Fall würde es also so aussehen:

// Automatisch generierte Klasse

namespace MyNamespace {
   public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol {
      public MyWebService() {
         string myString = "auto-generated constructor";
         OtherCode();
      }
   }
}

partial void OtherCode();

// Manuell erstellte Klasse, um den Standardkonstruktor zu überschreiben

partial void OtherCode()
{
   //do whatever extra stuff you wanted.
}

Es ist etwas eingeschränkt, und in diesem speziellen Fall, in dem Sie eine generierte Datei haben, die Sie ändern müssen, ist dies möglicherweise nicht die richtige Lösung, aber für andere, die bei diesem Versuch gestolpert sind, die Funktionalität in Teilklassen zu überschreiben, ist dies möglich sehr hilfreich sein.

3
rrreee

Das kannst du nicht tun. Ich schlage vor, eine Teilmethode zu verwenden, für die Sie dann eine Definition erstellen können. So etwas wie:

public partial class MyClass{ 

    public MyClass(){  
        ... normal construction goes here ...
        AfterCreated(); 
    }

    public partial void OnCreated();
}

Der Rest sollte ziemlich selbsterklärend sein.

BEARBEITEN: 

Ich möchte auch darauf hinweisen, dass Sie eine Schnittstelle für diesen Dienst definieren sollten, auf die Sie dann programmieren können, damit Sie keine Referenzen auf die tatsächliche Implementierung haben müssen. Wenn Sie dies getan hätten, hätten Sie noch ein paar andere Möglichkeiten.

2
jonnii

Ich denke, Sie könnten dies mit PostSharp tun, und es sieht so aus, als hätte jemand genau das getan, was Sie für Methoden in generierten Teilklassen wollen. Ich weiß nicht, ob dies leicht zu der Fähigkeit führt, eine Methode zu schreiben und den Konstruktor durch seinen Körper ersetzen zu lassen, da ich ihm noch keinen Schuss gegeben habe, aber es scheint einen Versuch wert zu sein.

Edit: das ist in der gleichen Richtung und sieht auch interessant aus.

2
cfeduke

Dies ist meiner Meinung nach ein Designfehler in der Sprache. Sie hätten mehrere Implementierungen einer Teilmethode zulassen sollen, die eine Nice-Lösung ergeben hätte.__ Auf eine noch schönere Weise kann der Konstruktor (auch eine Methode) dann auch einfach als partiell markiert werden und mehrere Konstruktoren mit derselben Signatur würden dies tun Beim Erstellen eines Objekts ausführen.

Die einfachste Lösung ist wahrscheinlich das Hinzufügen einer partiellen Konstruktormethode für jede zusätzliche Teilklasse:

public partial class MyClass{ 

    public MyClass(){  
        ... normal construction goes here ...
        OnCreated1(); 
        OnCreated2(); 
        ...
    }

    public partial void OnCreated1();
    public partial void OnCreated2();
}

Wenn Sie möchten, dass die Teilklassen nicht agnostisch sind, können Sie Reflection verwenden:

// In MyClassMyAspect1.cs
public partial class MyClass{ 

    public void MyClass_MyAspect2(){  
        ... normal construction goes here ...

    }

}

// In MyClassMyAspect2.cs
public partial class MyClass{ 

    public void MyClass_MyAspect1(){  
        ... normal construction goes here ...
    }
}

// In MyClassConstructor.cs
public partial class MyClass : IDisposable { 

    public MyClass(){  
       GetType().GetMethods().Where(x => x.Name.StartsWith("MyClass"))
                             .ForEach(x => x.Invoke(null));
    }

    public void Dispose() {
       GetType().GetMethods().Where(x => x.Name.StartsWith("DisposeMyClass"))
                             .ForEach(x => x.Invoke(null));
    }

}

Aber eigentlich sollten sie nur einige Sprachkonstrukte hinzufügen, um mit Teilunterricht zu arbeiten.

1
nreyntje

Nichts, woran ich denken kann. Der "beste" Weg, den ich finden kann, ist, einen Ctor mit einem Dummy-Parameter hinzuzufügen und folgendes zu verwenden:

public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol 
{
   public override MyWebService(int dummy) 
   { 
         string myString = "overridden constructor";
         //other code...
   }
}


MyWebService mws = new MyWebService(0);
0
James Curran

Bei einem von Visual Studio generierten Webdienstproxy können Sie keinen eigenen Konstruktor in der Teilklasse hinzufügen (dies ist zwar möglich, wird jedoch nicht aufgerufen). Stattdessen können Sie das Attribut [OnDeserialized] (oder [OnDeserializing]) verwenden, um Ihren eigenen Code an der Stelle einzuhaken, an der die Web-Proxy-Klasse instanziiert wird.

using System.Runtime.Serialization;

partial class MyWebService
{
     [OnDeserialized]
     public void OnDeserialized(StreamingContext context)
     {
         // your code here
     }
}
0
Edward

Manchmal haben Sie keinen Zugriff oder dürfen den Standardkonstruktor nicht ändern. Aus diesem Grund können Sie nicht den Standardkonstruktor zum Aufrufen von Methoden verwenden.

In diesem Fall können Sie einen anderen Konstruktor mit einem Dummy-Parameter erstellen und diesen neuen Konstruktor so einrichten, dass der Standardkonstruktor mit ": this ()" aufgerufen wird.

public SomeClass(int x) : this()
{
    //Your extra initialization here
}

Und wenn Sie eine neue Instanz dieser Klasse erstellen, übergeben Sie einfach Dummy-Parameter wie folgt:

SomeClass objSomeClass = new SomeClass(0);
0
Shadi