最新のC#アプリケーションで契約による小さな設計を試してみたかったので、次のような構文を使用したいと思いました。
public string Foo()
{
set {
Assert.IsNotNull(value);
Assert.IsTrue(value.Contains("bar"));
_foo = value;
}
}
ユニットテストフレームワークからこのような静的メソッドを取得できることは知っていますが、このようなものがすでに言語に組み込まれているかどうか、または何らかのフレームワークがすでに浮かんでいるかどうかを知りたいと思いました。独自のAssert関数を作成できますが、車輪の再発明はしたくありません。
C#4.0コードコントラクト
Microsoftは、.netフレームワークのバージョン4.0で、契約による設計用のライブラリをリリースしました。このライブラリの最も優れた機能の1つは、コードに設定したコントラクトの詳細を活用する静的分析ツール(FxCopに似ていると思います)も付属していることです。
Microsoftのリソースは次のとおりです。
その他のリソースは次のとおりです。
Spec# は人気があります Microsoft研究プロジェクト これにより、事後条件と事前条件のチェックなど、いくつかのDBC構造が可能になります。たとえば、バイナリ検索は、ループ不変条件とともに事前条件と事後条件を使用して実装できます。 この例など:
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 があります。
外部ライブラリを使用する以外に、System.Diagnosticsには単純なアサートがあります。
using System.Diagnostics
Debug.Assert(value != null);
Debug.Assert(value == true);
あまり役に立たない、私は知っています。
.net Fx4.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);
Moqのコードを見ると、事前条件と事後条件をチェックするための静的メソッドを提供する「Guard」というクラスが使用されていることがわかりました 。それはきちんとしていてとてもはっきりしていると思いました。これは、コードでコントラクトチェックによって設計を実装するときに私が考えていることを表しています。
例えば.
public void Foo(Bar param)
{
Guard.ArgumentNotNull(param);
}
契約チェックでデザインを表現するのもいい方法だと思いました。
LinFuのDesignByContractライブラリをお試しください:
あなたはチェックアウトしたいかもしれません 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");
}
}
}
}
_
_foo = value.Validation().NotNull("Foo").Contains("bar").Value;
を実行できるように、Validation拡張機能がビルダーであることを望みますが、それはそれです(幸い、オープンソースなので、ビルダーにするのは簡単な変更です)。
また、別の解決策として、 ドメイン検証を検討してください 。
最後に、 新しいM言語 、 Osloの一部として 、T-SQL検証と機能する検証テストを備えたCLRクラスの両方に変換されるエクステントとフィールドの制限をサポートします(ただしオスロはリリースから長い間離れています)。
最も簡単な方法、および.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;
}
}
私の現在のプロジェクト(2010年2月、VS 2008)では、選択しました http://lightcontracts.codeplex.com/
シンプルで、実行時の検証であり、奇妙な複雑さはありません。一部の「奇妙な」基本クラス、AOP、一部の開発者ワークステーションでは機能しないVS統合などから派生する必要はありません。
複雑さよりも単純さ。