Pergunta

Eu não acho que isso é possível, mas se é, então, eu preciso dele:)

Eu tenho um arquivo de proxy auto-gerada a partir da ferramenta de linha de comando wsdl.exe pelo Visual Studio 2008.

A saída proxy é classes parciais. Eu quero substituir o construtor padrão que é gerado. Prefiro não modificar o código, uma vez que é gerado automaticamente.

Eu tentei fazer outra classe parcial e redefinindo o construtor padrão, mas isso não funciona. Então eu tentei utilizando a substituição e novas palavras-chave, mas que não funciona.

Eu sei que poderia herdar da classe parcial, mas isso significaria que eu teria que mudar todo o nosso código fonte para apontar para a nova classe pai. Eu preferiria não ter de fazer isso.

Qualquer idéias, arounds de trabalho, ou 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...
      }
   }
}
Foi útil?

Solução

Isto não é possível. As classes parciais são essencialmente partes da mesma classe; nenhum método pode ser definido por duas vezes ou substituído, e que inclui o construtor.

Você poderia chamar um método no construtor, e apenas implementá-lo em outro arquivo de peça.

Outras dicas

Eu tinha um prolem semelhante, com o meu código gerado sendo criado por um arquivo dbml (estou usng aulas Linq-to-SQL).

Na classe gerado chama um vazio parcial chamado OnCreated () no final do construtor.

Para encurtar a história, se você quiser manter as coisas construtor importante a classe gerada faz para você (que você provavelmente deveria fazer), então em sua classe parcial criar o seguinte:

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

Hmmm, Eu acho que uma solução elegante seria o seguinte:

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

Esta abordagem tem algumas desvantagens (como tudo):

  1. Não está claro quando exatamente será executado o construtor da classe interna MyCustomization durante o procedimento de construção toda a classe AutogenCls.

  2. Se houver será necessário implementar a interface IDiposable para a classe MyCustomization para tratar corretamente a eliminação de recursos não gerenciados da classe MyCustomization, eu não sei (ainda) como acionar o método MyCustomization.Dispose () sem tocar o arquivo AutogenCls.cs ... (mas como eu disse 'ainda':)

Mas essa abordagem oferece grande separação de código gerado automaticamente -. Personalização inteira é separada no arquivo de código src diferente

aproveitar:)

Na verdade, esta é agora possível, já que os métodos parciais foram adicionados. Aqui está o doc:

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

Basicamente, a idéia é que você pode declarar e chamar um método em um arquivo onde você está definindo a classe parcial, mas na verdade não definem o método no arquivo. No outro arquivo, você pode, então, definir o método. Se você está construindo uma assembléia onde o método não está definido, então o ORM irá remover todas as chamadas para a função.

Assim, no caso acima, ficaria assim:

// classe gerado Auto

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

partial void OtherCode();

// manualmente criado classe, a fim de substituir o padrão construtor

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

Ele é um pouco limitado, e neste caso particular, onde você tem um arquivo gerado que você precisa alterar, pode não ser a solução certa, mas para outros que tropeçou neste tentando substituir funcionalidade em classes parciais , isso pode ser bastante útil.

O problema que o OP tem é que o proxy de referência web não gera quaisquer métodos parciais que você pode usar para interceptar o construtor.

Eu corri para o mesmo problema, e eu não posso apenas atualizar para WCF porque o serviço web que eu estou targetting não apoiá-lo.

Eu não queria alterar manualmente o código gerado automaticamente, porque ele vai ficar achatada se alguém invoca a geração de código.

Eu abordou o problema de um ângulo diferente. Eu sabia que minha iniciação precisava ser feito antes de um pedido, não realmente precisa ser feito no momento da construção, então eu só cancelou o método GetWebRequest assim.

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 é uma boa solução porque não envolve cortar o código gerado automaticamente, e ele se encaixa caso de uso exato de OP de realizar o login inicialização para um SoapHttpClientProtocol auto proxy gerado.

Você não pode fazer isso. Eu sugiro usar um método parcial que você pode, então, criar uma definição para. Algo como:

public partial class MyClass{ 

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

    public partial void OnCreated();
}

O resto deve ser bastante auto-explicativo.

EDIT:

Eu também gostaria de salientar que você deve ser a definição de uma interface para este serviço, que você pode, em seguida, programa para, assim você não tem que ter referências para a implementação real. Se você fez isso, então você teria que algumas outras opções.

Eu estou pensando que você pode ser capaz de fazer isso com PostSharp , e parece que alguém tenha feito apenas o que você quer para métodos em classes parciais gerados . Eu não sei se isso vai prontamente traduzir para a capacidade de escrever um método e ter seu corpo substituir o construtor como eu não deram-lhe um tiro, mas ainda parece um tiro pena.

Edit: isso é ao longo das mesmas linhas e também parece interessante.

Este é na minha opinião uma falha de projeto no idioma. Eles deveriam ter permitido várias implementações de um método parcial, que teria fornecido uma solução agradável. De uma forma ainda melhor o construtor (também um método) pode também ser simplesmente ser marcado construtores parciais e múltiplas com a mesma assinatura seria executado durante a criação de um objeto.

A solução mais simples é, provavelmente, para adicionar um método parcial 'construtor' per classe parcial extra:

public partial class MyClass{ 

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

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

Se você quiser as classes parciais para ser agnóstico sobre o outro, você pode usar a reflexão:

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

}

Mas realmente eles devem apenas adicionar mais algumas construções de linguagem para trabalhar com classes parciais.

Para um proxy de serviço Web gerado pelo Visual Studio, você não pode adicionar seu próprio construtor na classe parcial (assim você pode, mas ele não é chamado). Em vez disso, você pode usar o atributo [OnDeserialized] (ou [OnDeserializing]) para ligar em seu próprio código no ponto onde a classe de proxy web é instanciado.

using System.Runtime.Serialization;

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

Às vezes você não tem acesso ou não está autorizado a alterar o construtor padrão, por esta razão, você não pode ter o construtor padrão para chamar quaisquer métodos.

Neste caso, você pode criar outro construtor com um parâmetro fictício, e fazer este novo construtor para chamar o construtor padrão usando ": este ()"

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

E quando você cria uma nova instância dessa classe que você acabou de passar parâmetro fictício como este:

SomeClass objSomeClass = new SomeClass(0);

Nada que eu possa pensar. O "melhor" maneira que eu posso vir acima com é adicionar um ctor com um parâmetro fictício e uso que:

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top