Domanda

Non credo sia possibile, ma se è così ne ho bisogno :)

Ho un file proxy generato automaticamente dallo strumento da riga di comando wsdl.exe di Visual Studio 2008.

L'output del proxy è classi parziali. Voglio sovrascrivere il costruttore predefinito che viene generato. Preferirei non modificare il codice poiché è generato automaticamente.

Ho provato a creare un'altra classe parziale e a ridefinire il costruttore predefinito, ma non funziona. Ho quindi provato a utilizzare l'override e le nuove parole chiave, ma non funziona.

So che potrei ereditare dalla classe parziale, ma ciò significherebbe che dovrei cambiare tutto il nostro codice sorgente per puntare alla nuova classe genitore. Preferirei non doverlo fare.

Qualche idea, soluzione o hack?

//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...
      }
   }
}
È stato utile?

Soluzione

Questo non è possibile. Le classi parziali sono essenzialmente parti della stessa classe; nessun metodo può essere definito due volte o sovrascritto e questo include il costruttore.

È possibile chiamare un metodo nel costruttore e implementarlo solo nell'altro file di parti.

Altri suggerimenti

Ho avuto un prolem simile, con il mio codice generato creato da un file dbml (sto usando le classi Linq-to-SQL).

Nella classe generata chiama un vuoto parziale chiamato OnCreated () alla fine del costruttore.

Per farla breve, se vuoi mantenere le cose importanti del costruttore che la classe generata fa per te (cosa che probabilmente dovresti fare), quindi nella tua classe parziale crea quanto segue:

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

Hmmm, Penso che una soluzione elegante sarebbe la seguente:

//* 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
        }
    }
}

Questo approccio presenta alcuni inconvenienti (come tutto):

  1. Non è chiaro quando verrà eseguito esattamente il costruttore della classe interna MyCustomization durante l'intera procedura di costruzione della classe AutogenCls.

  2. Se sarà necessario implementare l'interfaccia IDiposable per la classe MyCustomization per gestire correttamente lo smaltimento delle risorse non gestite della classe MyCustomization, non so (ancora) come attivare il metodo MyCustomization.Dispose () senza toccando il file AutogenCls.cs ... (ma come ho detto "ancora" :)

Ma questo approccio offre una grande separazione dal codice generato automaticamente: l'intera personalizzazione è separata in diversi file di codice src.

divertiti :)

In realtà, questo è ora possibile, ora che sono stati aggiunti metodi parziali. Ecco il documento:

http://msdn.microsoft.com/en-us/library/ wa80x488.aspx

Fondamentalmente, l'idea è che puoi dichiarare e chiamare un metodo in un file in cui stai definendo la classe parziale, ma in realtà non definisci il metodo in quel file. Nell'altro file, è quindi possibile definire il metodo. Se si sta creando un assembly in cui il metodo non è definito, l'ORM rimuoverà tutte le chiamate alla funzione.

Quindi nel caso sopra sarebbe simile a questo:

// Classe generata automaticamente

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

partial void OtherCode();

// Classe creata manualmente per sovrascrivere il costruttore predefinito

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

È alquanto limitato, e in questo caso particolare, dove hai un file generato che dovresti modificare, potrebbe non essere la soluzione giusta, ma per gli altri che si sono imbattuti in questo tentativo di sovrascrivere la funzionalità in classi parziali , questo può essere molto utile.

Il problema che l'OP ha è che il proxy di riferimento web non genera alcun metodo parziale che puoi usare per intercettare il costruttore.

Ho riscontrato lo stesso problema e non posso semplicemente eseguire l'aggiornamento a WCF perché il servizio web a cui sto indirizzando non lo supporta.

Non volevo modificare manualmente il codice generato automaticamente perché verrà appiattito se qualcuno invoca mai la generazione del codice.

Ho affrontato il problema da una prospettiva diversa. Sapevo che la mia inizializzazione doveva essere eseguita prima di una richiesta, in realtà non doveva essere eseguita in fase di costruzione, quindi ho solo scavalcato il metodo GetWebRequest in questo modo.

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;
}

Questa è una buona soluzione perché non implica l'hacking del codice generato automaticamente e si adatta al caso d'uso esatto dell'OP di eseguire il login di inizializzazione per un proxy generato automaticamente da SoapHttpClientProtocol.

Non puoi farlo. Suggerisco di utilizzare un metodo parziale per il quale è possibile creare una definizione per. Qualcosa del tipo:

public partial class MyClass{ 

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

    public partial void OnCreated();
}

Il resto dovrebbe essere piuttosto autoesplicativo.

EDIT:

Vorrei anche sottolineare che dovresti definire un'interfaccia per questo servizio, a cui puoi quindi programmare, quindi non devi avere riferimenti all'implementazione effettiva. Se lo facessi, avresti qualche altra opzione.

Penso che potresti essere in grado di farlo con PostSharp e sembra che qualcuno abbia fatto ciò che desideri per metodi in classi parziali generate . Non so se questo si tradurrà prontamente nella capacità di scrivere un metodo e far sostituire il costruttore dal suo corpo poiché non gli ho ancora dato una possibilità, ma sembra che valga la pena provare.

Modifica: questo è sulla stessa linea e sembra anche interessante.

Questo è secondo me un difetto di progettazione nella lingua. Avrebbero dovuto consentire molteplici implementazioni di un metodo parziale, che avrebbe fornito una buona soluzione. In un modo ancora più bello il costruttore (anche un metodo) può quindi essere semplicemente contrassegnato come parziale e più costruttori con la stessa firma verrebbero eseguiti durante la creazione di un oggetto.

La soluzione più semplice è probabilmente quella di aggiungere un metodo "costruttore" parziale per ogni classe parziale parziale:

public partial class MyClass{ 

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

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

Se vuoi che le classi parziali siano agnostiche l'una sull'altra, puoi usare reflection:

// 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));
    }

}

Ma in realtà dovrebbero solo aggiungere altri costrutti di linguaggio per lavorare con classi parziali.

Per un proxy del servizio Web generato da Visual Studio, non è possibile aggiungere il proprio costruttore nella classe parziale (bene, ma non viene chiamato). Invece, puoi usare l'attributo [OnDeserialized] (o [OnDeserializing]) per agganciare il tuo codice nel punto in cui viene istanziata la classe proxy web.

using System.Runtime.Serialization;

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

A volte non hai accesso o non è consentito modificare il costruttore predefinito, per questo motivo non puoi avere il costruttore predefinito per chiamare alcun metodo.

In questo caso puoi creare un altro costruttore con un parametro fittizio e fare in modo che questo nuovo costruttore chiami il costruttore predefinito usando " ;: this () "

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

E quando crei una nuova istanza di questa classe, passi semplicemente un parametro fittizio come questo:

SomeClass objSomeClass = new SomeClass(0);

Nulla che mi venga in mente. Il "migliore" il modo in cui posso trovare è aggiungere un ctor con un parametro fittizio e usarlo:

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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top