10

私は次のような状況にあります。一部の.Netランタイムメソッドはうまく機能しないため、回避策を作成する必要があります。閉じたリーダーオブジェクトを返すことがあるので、次のSqlCommand.ExecuteReader()ようなコードが必要です。

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

これは、呼び出すすべてのコードを変更して、呼び出すExecuteReader()ようにMyExecuteReader()なり、メンテナンスが難しくなることを除いて、問題ありません。

私のコードのいずれかが呼び出されたいときはいつでも代わりに呼び出されることをどういうわけか宣言する方法はありSqlCommand.ExecuteReader()ますMyExecuteReader()か?事実上、既存のメソッドをまったく同じ署名と同じ名前を持つ別のメソッドに置き換えることは可能ですか?

4

4 に答える 4

12

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

最善のオプションは、別の名前で標準拡張メソッドを実装し、すべての使用法を置き換えることです。これは、大規模なコードベースでは多くの作業のように思われる可能性があり、将来的に人為的エラーが発生する可能性があります。誰かが元のメソッドに新しい呼び出しを追加します。ただし、1回限りのコストは、動作に変更を加えたことをコードが明示的に示しているという事実によって相殺されます。また、独自のカスタムFxCopルール(または定期的に実行している静的分析ツール)を作成することで、人的エラーを防ぐことができます。

于 2013-01-09T06:43:54.343 に答える
10

これは、モックを使用してテストコードを単体テストしようとする場合の問題に似ています。

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

したがって、次のようなコードを置き換えることになります。

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

と:

var sqlCommandFactory = new SqlCommandFactory();
using (ISqlCommand command = sqlCommandFactory.CreateSqlCommand(query))
{
    command.ExecuteReader();
}

まず、置換するメソッドを含むインターフェースを定義します。

public interface ISqlCommand
{
    SqlDataReader ExecuteReader();

    // further interface methods here...
}

SqlCommand次に、コンストラクターと同じシグニチャーを使用するファクトリを作成します。

internal class SqlCommandFactory
{
    bool _useMyClass = true;

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

MySqlCommand次に、クラスに代替コードを記述します。

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

.NETSqlCommandクラスは明らかに新しいインターフェイスを実装していないため、ISqlCommandこれを行うラッパークラスを作成します。

public SqlCommandWrapper : ISqlCommand
{
    SqlCommand _sqlCommand;

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

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

少し余分な作業がありますが、このメソッドの利点は、ユニットテスト(模擬ファクトリをコードに渡すことによって)を含め、実装を必要なものに変更できることです。

追加の作業は1回限りで、要求に応じて名前と元のメソッドシグネチャを保持する必要があります。これにより、特にあなた(またはあなたのチーム)がこのよく知られたパターンに慣れると、コードがより親しみやすく理解しやすくなります(カスタム/拡張メソッドと比較して)。

于 2013-01-09T06:58:36.890 に答える
3

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

しかし、私はあなたのコードを書き直す方がはるかに良いと信じているので、あなたのコードを読むかもしれない他の人(そして後であなた自身)には何が起こっているのかは明らかです:)

于 2013-01-09T06:57:19.420 に答える
1

私はあなたがそれをしたいとは思わない。コードを読むすべての人を混乱させるでしょう。

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

どうやら、誰かが.NETメソッドを注入する方法を理解することができたようです。

これはおそらくそれが価値があるよりもはるかに多くの問題になることを覚えておいてください。あらゆる種類の追加ソフトウェアがインストールされているあらゆる種類のプラットフォームで広範囲にQAを行う必要があります(1種類のアンチウイルスがコードを破壊する可能性があります)。つまり、実際には、他のすべての人が提案したことを実行してください。拡張メソッドを作成し、コードベース全体を検索して置換するだけです。

于 2013-01-09T06:49:12.623 に答える