1

メソッドの事前条件と事後条件をチェックするための (非常に小さな) フレームワークを作成しています。エントリ ポイントは次のとおりです (簡単にメソッドにすることができますが、それは問題ではありません)。

public static class Ensures {
    public static Validation That {
        get { ... }
    }
}

public static class Requires {
    public static Validation That {
        get { ... }
    }
}

明らかに、事後条件のチェックはコストがかかる可能性があり、メソッドにバグがない場合は実際には必要ありません。したがって、次のように機能するメソッドが必要です。

public static class Ensures {
    [ConditionalCallingCode("DEBUG")]
    public static Validation ThatDuringDebug {
        get { ... }
    }
}

whereConditionalCallingCodeAttributeは、呼び出しコードが DEBUG シンボルを定義してコンパイルされている場合にのみ、このメソッドを実行する必要があることを意味します。これは可能ですか?

クライアントコードを次のようにしたい:

public class Foo {
    public void Bar() {
        ... // do some work
        Ensures.That // do these checks always
            .IsNotNull(result)
            .IsInRange(result, 0, 100);

        Ensures.WhileDebuggingThat // only do these checks in debug mode
            .IsPositive(ExpensiveCalculation(result));

        return result;
    }
}

もちろん、WhileDebuggingThat を提供することはできません。次に、クライアント コードは次のようになります。

public class Foo {
    public void Bar() {
        ... // do some work
        Ensures.That // do these checks always
            .IsNotNull(result)
            .IsInRange(result, 0, 100);

        #ifdef DEBUG
        Ensures.That // only do these checks in debug mode
            .IsPositive(ExpensiveCalculation(result));
        #endif

        return result;
    }
}

これは、他に何もうまくいかない場合のフォールバック プランですが、DRY がひどく壊れます。

私が理解しているように、でマークWhileDebuggingThatすると、このライブラリを参照するアセンブリではなく[Conditional("DEBUG")]、ライブラリのコンパイル中に DEBUG が定義されているかどうかに応じて、このメソッドが発行されます (または発行されません) 。したがって、これを行ってから、ライブラリのユーザーに、コードのデバッグ ビルドをライブラリのデバッグ ビルドにリンクし、リリース ビルドをリリース ビルドにリンクするように指示するドキュメントを作成できます。これは最善の解決策とは思えません。

最後に、ライブラリのユーザーに、プロジェクト内でこのクラスを定義するように指示できます。

using ValidationLibrary;
public static class EnsuresWhileDebugging {
    [Conditional("DEBUG")]
    public static Validation That() {
        return Ensures.That;
    }
}

私が見る限り、これも同様に機能するはずですが、DRY の原則を少しでも破る必要があります。

4

8 に答える 8

3

これは、メソッドではなくプロパティで作業する以外に、通常のConditionalAttributeではできないことですか? プロパティの代わりにメソッドを使用するように、呼び出し方法を変更する必要があるかもしれません。また、値を返すという事実が問題を引き起こす可能性があります。

あなたのフレームワークがどのように使用されているかを示していただけると大変助かります。

考慮すべきもう1つのことは、ライブラリのさまざまなバイナリビルドを提供することです。これにより、呼び出し元は実際にはチェックを行わない別のバージョンを提供できます。繰り返しますが、提供したコードだけではわかりにくいです。

于 2008-12-27T11:43:06.403 に答える
1

ここで見つかった解決策は、実際のチェックよりも遅くなります。また、 のようにコンパイラに組み込まれないためConditionalAttribute、パラメータは引き続き計算されます。事後条件が次のように非常に複雑な場合

Ensures.That.IsPositive(ExpensiveCalculation(result));

icelava の提案を使用して、呼び出しアセンブリを反映して、それがデバッグまたはリリースでビルドされているかどうかを確認することを検討できますが、計算を遅らせるために何らかのデリゲートを使用して、必要なときにのみ実行されるようにする必要があります例えば:

Ensures.WhileDebugging.That. IsPositive(() => ExpensiveCalculation(result));

IsPositive 関数は、ラムダを実行してその結果を確認する必要があります。これは、計算する必要があるかどうかを確認するために反映した後でのみ行われます。

于 2008-12-28T13:11:12.310 に答える
0

よくわかりませんが、ConditionalAttributeを使用できると思います。呼び出しを発行するかどうかは、ライブラリではなく、ユーザーのビルドのタイプによって異なります。これは、ReflectorまたはILDasmで確認できます。サンプルをコンパイルし、Reflector(ILDasm)で、サンプルプロジェクトで呼び出しが発生したかどうかを確認します。

于 2008-12-30T19:27:57.447 に答える
0

私が欲しいものはただ利用できないようです。検証チェックをにラップできるように、からValidationへの暗黙的な変換を提供することをおそらく決心します。boolDebug.Assert()

于 2008-12-29T12:16:54.663 に答える
0

たとえば、値がプロジェクトのユーザー設定から取得される場合、プログラムがコンパイルされた後でも、ブール値を使用して Debug Assert メソッドを設定/変更できます。

Debug.Assert(!Properties.Settings.Default.UseAutoDebug);
于 2008-12-30T02:10:39.707 に答える
0

私はこれが発生しました:プロジェクトAはBの1つの関数を呼び出します。Bには次の関数が含まれます:Assembly.GetCallingAssembly()。FullNameモードデバッグでBをビルドしてから実行すると、この関数はプロジェクトAの名前を返し、モードリリースでビルドすると名前を返しますプロジェクトBの理由はわかりません。私をサポートしてくださいありがとう

于 2009-06-16T07:12:49.520 に答える
0

私は入浴して家を出るつもりなので、これを試していません.

  1. Assembly.GetCallingAssembly() を呼び出して、現在実行中のメソッドを呼び出すメソッド (クラス) のアセンブリを取得します。
  2. その Assembly オブジェクトに対してチェックを実行して、それが Release または Debug build であるかどうかを確認します
于 2008-12-27T12:43:19.540 に答える
0

あなたがしていることのほとんどは、 を使用してすでにカバーされているようですDebug.Assert()

さらに言えば、このコードはデバッグ モードでのみ実行されます (ただし、catch ブロックの遅さに我慢する必要があります)。

try
{
     Debug.Assert(false);
}
catch (Exception e)
{
     // will only and always run in debug mode

}
于 2008-12-27T15:17:00.153 に答える