39

私は最新の C# アプリケーションでコントラクトによる小さな設計を試してみたかったので、次のような構文を使用したいと考えていました。

public string Foo()
{
    set {
        Assert.IsNotNull(value);
        Assert.IsTrue(value.Contains("bar"));
        _foo = value;
    }
}

単体テスト フレームワークからこのような静的メソッドを取得できることはわかっていますが、このようなものが既に言語に組み込まれているのか、それとも何らかのフレームワークがすでに存在しているのかを知りたかったのです。車輪を再発明したくないだけで、独自のアサート関数を作成できます。

4

8 に答える 8

86

C# 4.0 コード コントラクト

Microsoft は、.net フレームワークのバージョン 4.0 で契約による設計用のライブラリをリリースしました。そのライブラリの最もクールな機能の 1 つは、コードに配置したコントラクトの詳細を活用する静的分析ツール (FxCop に似ていると思います) も付属していることです。

Microsoft のリソースを次に示します。

その他のリソースは次のとおりです。

于 2008-11-06T04:48:31.903 に答える
23

Spec#は、 post および pre 条件のチェックなど、一部の DBC 構造を可能にする、 Microsoftの人気のある研究プロジェクトです。たとえば、二分探索は、ループの不変条件とともに前後の条件を使用して実装できます。この例とその他:

 public static int BinarySearch(int[]! a, int key)
    requires forall{int i in (0: a.Length), int j in (i: a.Length); a[i] <= a[j]};
    ensures 0 <= result ==> a[result] == key;
    ensures result < 0 ==> forall{int i in (0: a.Length); a[i] != key};
 {
   int low = 0;
   int high = a.Length - 1;

   while (low <= high)
     invariant high+1 <= a.Length;
     invariant forall{int i in (0: low); a[i] != key};
     invariant forall{int i in (high+1: a.Length); a[i] != key};
   {
     int mid = (low + high) / 2;
     int midVal = a[mid];

     if (midVal < key) {
       low = mid + 1;
     } else if (key < midVal) {
       high = mid - 1;
     } else {
       return mid; // key found
     }
   }
   return -(low + 1);  // key not found.
 }

Spec# 言語を使用すると、コンパイル時に DBC コンストラクトがチェックされることに注意してください。これは、私にとって、DBC を利用する最良の方法です。多くの場合、実行時のアサーションに依存することは本番環境で頭痛の種になり、一般的には代わりに例外を使用することを選択します。

DBC の概念を第一級の構成要素として取り入れている言語は他にもあります。つまり、.NET プラットフォームでも使用できるEiffelです。

于 2008-11-04T03:55:50.420 に答える
11

外部ライブラリを使用する以外に、System.Diagnostics に単純なアサートがあります。

using System.Diagnostics

Debug.Assert(value != null);
Debug.Assert(value == true);

あまり役に立ちませんね。

于 2008-11-04T03:54:48.580 に答える
7

.net Fx 4.0 には答えがあります。

System.Diagnostics.Contracts

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

Contract.Requires(newNumber > 0, “Failed contract: negative”);
Contract.Ensures(list.Count == Contract.OldValue(list.Count) + 1);
于 2010-07-01T07:07:29.697 に答える
2

Moq のコードを調べると、「Guard」というクラスを使用していることがわかりました。このクラスは、事前および事後条件をチェックするための静的メソッドを提供します。すっきりしていてとてもわかりやすいと思いました。これは、自分のコードでコントラクト チェックによる設計を実装するときに考えていたことを表しています。

例えば

public void Foo(Bar param)
{
   Guard.ArgumentNotNull(param);
} 

コントラクトチェックによるデザインの表現がうまいなと思いました。

于 2008-11-04T05:03:03.310 に答える
1

最も簡単な方法、および.NET Framework自体で使用される方法は、次のことを行うことです。

public string Foo()
{
    set {
        if (value == null)
            throw new ArgumentNullException("value");
        if (!value.Contains("bar"))
            throw new ArgumentException(@"value should contain ""bar""", "value");

        _foo = value;
    }
}
于 2011-03-04T10:54:54.270 に答える
1

nVentive Umbrellaをチェックしてみてください。

using System;
using nVentive.Umbrella.Validation;
using nVentive.Umbrella.Extensions;

namespace Namespace
{
    public static class StringValidationExtensionPoint
    {
        public static string Contains(this ValidationExtensionPoint<string> vep, string value)
        {
            if (vep.ExtendedValue.IndexOf(value, StringComparison.InvariantCultureIgnoreCase) == -1)
                throw new ArgumentException(String.Format("Must contain '{0}'.", value));

            return vep.ExtendedValue;
        }
    }

    class Class
    {
        private string _foo;
        public string Foo
        {
            set
            {
                _foo = value.Validation()
                    .NotNull("Foo")
                    .Validation()
                    .Contains("bar");
            }
        }
    }
}

Validation 拡張機能がビルダーであることを願っていますが_foo = value.Validation().NotNull("Foo").Contains("bar").Value;、それがそのままです (幸いなことにオープン ソースであるため、ビルダーにするのは些細な変更です)。

また、代替ソリューションとして、domain validation を検討できます。

最後に、新しい M 言語は、Oslo の一部として、エクステントとフィールドの制限をサポートします。これは、T-SQL 検証と機能する検証テストを備えた CLR クラスの両方に変換されます (ただし、Oslo はリリースから長い時間がかかります)。

于 2008-11-04T05:00:41.567 に答える
1

現在のプロジェクト (2010 年 2 月、VS 2008) では、http://lightcontracts.codeplex.com/を選択しました。

シンプルで、奇妙な複雑さのない単なるランタイム検証であり、いくつかの「奇妙な」基本クラスから派生させる必要はなく、AOP や、一部の開発者ワークステーションでは機能しない VS 統合なども必要ありません。

複雑さよりもシンプルさ。

于 2010-02-26T01:25:40.597 に答える