53

私はこれが可能だとは思いませんが、もしそうなら私はそれが必要です:)

VisualStudio2008によってwsdl.exeコマンドラインツールから自動生成されたプロキシファイルがあります。

プロキシ出力は部分クラスです。生成されたデフォルトのコンストラクターをオーバーライドしたいと思います。自動生成されるため、コードを変更したくありません。

別の部分クラスを作成してデフォルトのコンストラクターを再定義しようとしましたが、機能しません。次に、overrideキーワードとnewキーワードを使用してみましたが、機能しません。

部分クラスから継承できることはわかっていますが、それは、新しい親クラスを指すようにすべてのソースコードを変更する必要があることを意味します。私はむしろこれをする必要はありません。

アイデア、回避策、またはハックはありますか?

//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...
      }
   }
}
4

12 に答える 12

70

生成されたコードがDBMLファイルによって作成されているという同様の問題がありました(Linq-to-SQLクラスを使用しています)。

生成されたクラスでは、コンストラクターの最後で OnCreated() という部分的な void を呼び出します。

簡単に言えば、生成されたクラスが行う重要なコンストラクターを保持したい場合 (おそらくそうするべきです)、部分クラスで次を作成します。

partial void OnCreated()
{
    // Do the extra stuff here;
}
于 2010-01-09T01:24:52.737 に答える
40

これは不可能です。部分クラスは基本的に同じクラスの一部です。メソッドを2回定義したり、オーバーライドしたりすることはできません。これにはコンストラクターが含まれます。

コンストラクターでメソッドを呼び出して、他のパーツファイルにのみ実装することができます。

于 2008-10-29T18:08:00.987 に答える
13

うーん、エレガントな解決策の1つは次のとおりだと思います。

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

このアプローチにはいくつかの欠点があります (すべての場合と同様):

  1. AutogenCls クラスの構築手順全体で、MyCustomization 内部クラスのコンストラクターが正確にいつ実行されるかは明確ではありません。

  2. MyCustomization クラスのアンマネージ リソースの破棄を正しく処理するために MyCustomization クラスに IDiposable インターフェイスを実装する必要がある場合、AutogenCls.cs ファイルに触れずに MyCustomization.Dispose() メソッドをトリガーする方法が (まだ) わかりません。 ...(しかし、「まだ」と言ったように:)

しかし、このアプローチは、自動生成されたコードからの大きな分離を提供します - カスタマイズ全体が異なる src コード ファイルに分離されます。

楽しい :)

于 2010-04-02T20:57:23.660 に答える
4

実際、部分的なメソッドが追加されたので、これが可能になりました。ドキュメントは次のとおりです。

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

基本的には、部分クラスを定義している 1 つのファイルでメソッドを宣言して呼び出すことができますが、そのファイルで実際にメソッドを定義することはできません。他のファイルでは、メソッドを定義できます。メソッドが定義されていないアセンブリを構築している場合、ORM は関数へのすべての呼び出しを削除します。

したがって、上記の場合は次のようになります。

//自動生成されたクラス

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

partial void OtherCode();

//デフォルトのコンストラクターをオーバーライドするために手動で作成されたクラス

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

これは多少制限されており、この特定のケースでは、変更する必要がある生成されたファイルがあるため、適切な解決策ではない可能性がありますが、部分クラスの機能をオーバーライドしようとしてこれに出くわした他の人にとっては、これは可能ですかなり役に立ちます。

于 2011-09-27T15:52:40.500 に答える
3

OP が抱えている問題は、Web 参照プロキシが、コンストラクターをインターセプトするために使用できる部分メソッドを生成しないことです。

私は同じ問題に遭遇しました。対象としている Web サービスが WCF をサポートしていないため、WCF にアップグレードすることはできません。

自動生成されたコードを手動で修正したくなかったのは、誰かがコード生成を呼び出した場合に平坦化されてしまうからです。

私は別の角度から問題に取り組みました。リクエストの前に初期化を行う必要があることはわかっていましたが、実際には構築時に行う必要はなかったので、GetWebRequest メソッドをそのようにオーバーライドしました。

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

自動生成されたコードをハッキングする必要がなく、SoapHttpClientProtocol 自動生成プロキシの初期化ログインを実行するという OP の正確な使用例に適合するため、これは優れたソリューションです。

于 2013-06-17T16:06:36.670 に答える
2

あなたはこれを行うことはできません。定義を作成できる部分的なメソッドを使用することをお勧めします。何かのようなもの:

public partial class MyClass{ 

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

    public partial void OnCreated();
}

残りはかなり自明であるはずです。

編集:

また、このサービスのインターフェイスを定義する必要があることも指摘しておきます。このインターフェイスをプログラムして、実際の実装を参照する必要はありません。これを行った場合、他のいくつかのオプションがあります。

于 2008-10-29T18:10:25.787 に答える
2

PostSharpでこれを行うことができるかもしれないと考えています。生成された部分クラスのメソッドに対して、誰かがまさにあなたが望むことを行ったようです。まだ試していないので、これがメソッドを記述してその本体をコンストラクターに置き換える機能にすぐに変換されるかどうかはわかりませんが、試してみる価値があるようです。

編集:これは同じ線に沿っており、興味深いものです。

于 2008-10-29T18:28:24.360 に答える
2

アクセス権がないか、デフォルトのコンストラクターを変更することが許可されていない場合があります。このため、デフォルトのコンストラクターでメソッドを呼び出すことはできません。

この場合、ダミー パラメーターを使用して別のコンストラクターを作成し、この新しいコンストラクターが ": this()" を使用してデフォルトのコンストラクターを呼び出すようにすることができます。

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

そして、このクラスの新しいインスタンスを作成するときは、次のようにダミー パラメータを渡すだけです。

SomeClass objSomeClass = new SomeClass(0);
于 2012-02-14T09:49:03.997 に答える
1

私の意見では、これは言語の設計上の欠陥です。1 つの部分メソッドの複数の実装を許可する必要がありました。さらに良い方法では、コンストラクター (メソッドでもあります) を単純に部分的にマークすることもでき、オブジェクトの作成時に同じ署名を持つ複数のコンストラクターが実行されます。

最も簡単な解決策は、おそらく追加の部分クラスごとに 1 つの部分「コンストラクター」メソッドを追加することです。

public partial class MyClass{ 

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

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

部分クラスを互いに不可知にしたい場合は、リフレクションを使用できます。

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

}

しかし、実際には、部分クラスを操作するために、言語構造をさらに追加する必要があります。

于 2010-12-30T11:54:42.240 に答える
0

Visual Studioによって生成されたWebサービスプロキシの場合、部分クラスに独自のコンストラクターを追加することはできません(できますが、呼び出されません)。代わりに、[OnDeserialized]属性(または[OnDeserializing])を使用して、Webプロキシクラスがインスタンス化された時点で独自のコードをフックできます。

using System.Runtime.Serialization;

partial class MyWebService
{
     [OnDeserialized]
     public void OnDeserialized(StreamingContext context)
     {
         // your code here
     }
}
于 2011-02-22T09:53:32.267 に答える
-1

私が考えることは何もありません。私が思いつく「最良の」方法は、ダミーパラメーターを持つctorを追加し、それを使用することです。

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);
于 2008-10-29T18:07:04.903 に答える