2013-01-09 12 views
10

私は次のような状況があります。一部の.Netランタイムメソッドがうまく機能せず、回避策を策定する必要があります。 SqlCommand.ExecuteReader()は時々閉じリーダーオブジェクトを返し、私はこのようなコードを持ってしたいがありますように:C#のメソッドを同じ名前とシグネチャで置き換えることはできますか?

SqlDataReader MyExecuteReader(this SqlCommand command) 
{ 
    var reader = command.ExecuteReader(); 
    if(reader.IsClosed()) { 
     throw new ClosedReaderReturnedException(); 
    } 
    return reader; 
} 

これはちょうどいいと思い、私は今それが今MyExecuteReader()を呼び出すようにExecuteReader()を呼び出すすべてのコードを変更する必要があります以外とメンテナンスが難しくなります。

私のコードのいずれかがSqlCommand.ExecuteReader()と呼ばれる代わりにMyExecuteReader()が呼び出されると、何とか宣言する方法がありますか?効果的に、既存のメソッドを、全く同じシグネチャと同じ名前を持つ別のメソッドに置き換えることは可能ですか?

+12

は私にとっては悪い考えです。 – lahsrah

+0

オーバーロードのように見えるように、いくつかの余分なオプションのパラメータで拡張メソッドを使用することはできますか?申し訳ありませんが、私はそれに答える代わりに質問しています。 – shahkalpesh

+0

プロファイリングAPIを使用しているか、何かが本当にハックしている可能性があります。カップル年前からこの1つがここにありますhttp://www.codeproject.com/Articles/37549/CLR-Injection-Runtime-Method-Replacer butsは本当にハックです – AbdElRaheim

答えて

9

これは、モックを使用してテストコードをユニット化しようとするときの問題と似ています。

一方的に、SqlCommandのコードを、ExecuteReaderメソッドを持つインターフェイスを実装するオブジェクトに置き換えます。おそらく、ファクトリパターンを使用して、オブジェクトをより簡単に置き換えることができます。

ですから、このようなコード置き換えます:次に作成

public interface ISqlCommand 
{ 
    SqlDataReader ExecuteReader(); 

    // further interface methods here... 
} 

まずあなたが代わりに使用するメソッドが含まれているインタフェースを定義する
var sqlCommandFactory = new SqlCommandFactory(); 
using (ISqlCommand command = sqlCommandFactory.CreateSqlCommand(query)) 
{ 
    command.ExecuteReader(); 
} 

:と

using (SqlCommand command = new SqlCommand(query)) 
{ 
    command.ExecuteReader(); 
} 

SqlCommandコンストラクタと同じシグネチャを使用するファクトリ:

internal class SqlCommandFactory 
{ 
    bool _useMyClass = true; 

    public ISqlCommand CreateSqlCommand(string query) 
    { 
     if (_useMyClass) 
     { 
      return new MySqlCommand(query); 
     } 
     else 
     { 
      return new SqlCommandWrapper(query); 
     } 
    } 
} 

その後、MySqlCommandクラスであなたの代替コードを書く:.NET SqlCommandクラスとして

public MySqlCommand : ISqlCommand 
{ 
    public SqlDataReader ExecuteReader() 
    { 
     // your new code here 
    } 
} 

を明らかに、新しいISqlCommandインタフェースを実装し、これを行うラッパークラスを作成しません。

public SqlCommandWrapper : ISqlCommand 
{ 
    SqlCommand _sqlCommand; 

    public SqlCommandWrapper(string query) 
    { 
     _sqlCommand = new SqlCommand(query); 
    } 

    public SqlDataReader ExecuteReader() 
    { 
     _sqlCommand.ExecuteReader(); 
    } 
} 

少し余分な作業ですが、この方法の利点は、実装をあなたのものに変更できることです(あなたのコードにモックファクトリーを渡すことによる)ユニットテストのためのものを含む

余分な作業は一回限りで、必要に応じて名前と元のメソッドの署名を保持する必要があります。これは、特にあなた(またはあなたのチーム)がこのよく知られているパターンに慣れたときに、あなたのコードをより使い慣れたものにして理解しやすくします(カスタム/拡張メソッドと比較して)。

12

いいえ、お望みのものはサポートされていません。クラスが封印されておらず、メソッドが静的でない場合は、異なる名前空間に同じ名前のクラスを継承し、usingを変更してメソッドをオーバーライドできます。しかし、それは限られた解決策です。

あなたの最善の選択肢は、別名でstandart拡張メソッドを実装し、すべての用途を置き換えることです。これは、大規模なコードベースで多くの作業が行われているように思えるかもしれません。元のメソッドに新しい呼び出しを追加した人のエラーが発生する可能性があります。ただし、一度のコストは、コードが現在、動作に変更を加えたことを明示的に示していることによって相殺されます。独自のカスタムFxCopルール(または定期的に実行している静的解析ツール)を作成することで、人的ミスを防ぐことができます。

+4

私は、Visual Studioにはグローバルソリューションの検索と置換があると付け加えます。 –

1

私はあなたがそれをしたいとは思わない。コードを読んだ人は誰もが混乱するでしょう。

しかし、私はそれができないと信じていますが、長い間サポートされているとは保証されていません。昔は、DLLにエクスポートされた関数の代わりに関数を注入することができました。ウイルス対策プログラムはこの手法を使用していました。

どうやら、誰かがそれは価値があるよりも、これはおそらく、多くのトラブルになります覚えておいてくださいinject .NET methods.

する方法を見つけ出すことができました。さまざまな種類のソフトウェアがインストールされた状態で、あらゆる種類のプラットフォームで幅広くQAを実行する必要があります(ある種類のウイルス対策ではコードが壊れる可能性があります)。だから、実際には他の人たちが提案したことを実行してください。拡張メソッドを作成し、コードベース全体を検索して置き換えるだけです。

+0

その場でメソッドをインジェクトするだけでは、あまりにも多くの作業が必要になるだけでなく、いつでも破損する可能性がありますが、完全な信頼コードの実行のためにのみ動作します。 CASは中程度または低い信頼のサンドボックスのようなものを防ぎます。 –

+1

これは私がそれをしないことを勧めた理由です。 – zmbq

3

さて、あなたはここで行わようにILを書き換えるためにセシルのようなライブラリを使用することができます:http://plaureano.blogspot.dk/2011/05/introduction-to-il-rewriting-with-cecil.html?m=1

しかし、私はあなたのコードを書き換える方法で優れていると信じていますので、それは他の誰にも明らかである(と自分自身後で)あなたのコードを読んでいる可能性があります。

関連する問題