Pregunta

No creo que esto sea posible, pero si es entonces lo necesito :)

Tengo un archivo proxy generado automáticamente desde la herramienta de línea de comandos wsdl.exe de Visual Studio 2008.

La salida del proxy es clases parciales. Quiero anular el constructor predeterminado que se genera. Prefiero no modificar el código ya que se genera automáticamente.

Intenté crear otra clase parcial y redefinir el constructor predeterminado, pero eso no funciona. Luego intenté usar las palabras clave de reemplazo y nuevas, pero eso no funciona.

Sé que podría heredar de la clase parcial, pero eso significaría que tendría que cambiar todo nuestro código fuente para apuntar a la nueva clase padre. Preferiría no tener que hacer esto.

¿Alguna idea, trabajo, o trucos?

//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...
      }
   }
}
¿Fue útil?

Solución

Esto no es posible. Las clases parciales son esencialmente partes de la misma clase; ningún método puede definirse dos veces o sobrescribirse, y eso incluye al constructor.

Puede llamar a un método en el constructor y solo implementarlo en el otro archivo de parte.

Otros consejos

Tuve un problema similar, con mi código generado creado por un archivo dbml (estoy usando clases de Linq a SQL).

En la clase generada, llama a un vacío parcial llamado OnCreated () al final del constructor.

Para resumir, si desea mantener las cosas importantes del constructor que la clase generada hace por usted (lo que probablemente debería hacer), cree en su clase parcial lo siguiente:

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

Hmmm, Creo que una solución elegante sería la siguiente:

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

Este enfoque tiene algunos inconvenientes (como todo):

  1. No está claro cuándo se ejecutará exactamente el constructor de la clase interna MyCustomization durante todo el procedimiento de construcción de la clase AutogenCls.

  2. Si será necesario implementar la interfaz IDiposable para que la clase MyCustomization maneje correctamente la eliminación de los recursos no administrados de la clase MyCustomization, no sé (todavía) cómo activar el método MyCustomization.Dispose () sin tocando el archivo AutogenCls.cs ... (pero como dije 'todavía' :)

Pero este enfoque ofrece una gran separación del código generado automáticamente: la personalización completa se separa en un archivo de código src diferente.

disfruta :)

En realidad, esto ahora es posible, ahora que se han agregado métodos parciales. Aquí está el documento:

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

Básicamente, la idea es que puede declarar y llamar a un método en un archivo donde está definiendo la clase parcial, pero en realidad no puede definir el método en ese archivo. En el otro archivo, puede definir el método. Si está construyendo un ensamblaje donde el método no está definido, entonces el ORM eliminará todas las llamadas a la función.

Entonces, en el caso anterior, se vería así:

// Clase generada automáticamente

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

partial void OtherCode();

// Clase creada manualmente para anular el constructor predeterminado

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

Es algo limitado, y en este caso particular, donde tiene un archivo generado que necesitaría modificar, puede que no sea la solución correcta, pero para otros que se tropezaron con este intento de anular la funcionalidad en clases parciales , esto puede ser muy útil.

El problema que tiene el OP es que el proxy de referencia web no genera ningún método parcial que pueda usar para interceptar el constructor.

Me encontré con el mismo problema, y ??no puedo simplemente actualizarme a WCF porque el servicio web al que me dirijo no lo admite.

No quería modificar manualmente el código generado automáticamente porque se aplanará si alguien invoca la generación de código.

He abordado el problema desde un ángulo diferente. Sabía que mi inicialización debía realizarse antes de una solicitud, realmente no era necesario hacerlo en el momento de la construcción, por lo que simplemente anulé el método GetWebRequest de esta manera.

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

Esta es una buena solución porque no implica piratear el código generado automáticamente, y se ajusta al caso de uso exacto del OP de realizar el inicio de sesión de inicialización para un proxy generado automáticamente SoapHttpClientProtocol.

No puedes hacer esto. Sugiero usar un método parcial para el que luego puede crear una definición. Algo así como:

public partial class MyClass{ 

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

    public partial void OnCreated();
}

El resto debería explicarse bastante por sí mismo.

EDITAR:

También me gustaría señalar que debe definir una interfaz para este servicio, que luego puede programar, para que no tenga que tener referencias a la implementación real. Si hicieras esto, tendrías algunas otras opciones.

Estoy pensando que podrías hacer esto con PostSharp , y parece que alguien lo ha hecho lo que desea para los métodos en las clases parciales generadas . No sé si esto se traducirá fácilmente en la capacidad de escribir un método y hacer que su cuerpo reemplace al constructor, ya que aún no le he dado una oportunidad, pero parece que vale la pena intentarlo.

Edite: esto está en la misma línea y también parece interesante.

En mi opinión, esto es un defecto de diseño en el lenguaje. Deberían haber permitido múltiples implementaciones de un método parcial, que hubieran brindado una buena solución. De una manera aún más agradable, el constructor (también un método) también se puede marcar simplemente como parcial y se ejecutarían múltiples constructores con la misma firma al crear un objeto.

La solución más simple es probablemente agregar un método parcial de "constructor" por clase parcial extra:

public partial class MyClass{ 

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

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

Si quieres que las clases parciales sean agnósticas entre sí, puedes usar la reflexión:

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

}

Pero realmente solo deberían agregar algunas construcciones de lenguaje más para trabajar con clases parciales.

Para un proxy de servicio web generado por Visual Studio, no puede agregar su propio constructor en la clase parcial (bueno, puede, pero no se llama). En su lugar, puede usar el atributo [OnDeserialized] (o [OnDeserializing]) para enlazar su propio código en el punto donde se crea una instancia de la clase de proxy web.

using System.Runtime.Serialization;

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

A veces no tiene acceso o no está permitido cambiar el constructor predeterminado, por esta razón no puede tener el constructor predeterminado para llamar a ningún método.

En este caso, puede crear otro constructor con un parámetro ficticio y hacer que este nuevo constructor llame al constructor predeterminado utilizando " ;: this () "

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

Y cuando creas una nueva instancia de esta clase, simplemente pasas un parámetro ficticio como este:

SomeClass objSomeClass = new SomeClass(0);

Nada en lo que pueda pensar. El " mejor " La forma en que puedo llegar es agregar un ctor con un parámetro ficticio y 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);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top