基礎からの
Code Contracts

    @neuecc – 2011/5/23
Profile
 Twitter
        => @neuecc
 Blog => http://neue.cc/
 HNは"neuecc" 読むときは“のいえ”で
     ドメ゗ン繋いだだけで特に意味はなく発音不能のた
      め(ccは声に出しにくいのでスルーという適当対応)
 Microsoft
      MVP for Visual C#(2011/4-)
 公開してるラ゗ブラリとか
     linq.js
     DynamicJson
     Chaining Assertion
     DbExecutor <- (ちょっとだけ)Code Contracts使った
First Step
Code Contracts
 .NET4から標準搭載された?
 mscorlibにSystem.Diagnostics.Contracts
 (主に)その中のContractクラスのメソッド群
何か動かないよ?
 よくあるnullチェックをしてみようと思った
     Contract.Requiresは事前条件
     引数がnullだったら契約違反という感じにしたい

static void Hoge(string arg)
{
    Contract.Requires(arg != null);
}


 が、実行しても無反応
 Conditional属性がついているのでコンパ゗ル時に
  消える(条件付きメソッド、DEBUGとかでお馴染み)
     条件はCONTRACTS_FULL(但し自分で足す意味はない)
何か動かないよ? Part2
 よくあるnullチェックをしてみようと思った                                 again
     Contract.Requires<TException>も事前条件
     引数がnullだったら契約違反で例外ぶん投げたい

static void Hoge(string arg)
{
    Contract.Requires<ArgumentNullException>(arg != null);
}


 が、変なゕサートが飛ぶ
 そしてゕプリは強制終了
 リラ゗ターがmustだと?
つまるところ
 Code   Contractsの利用にはリラ゗ターが必要

     最終的な配布物はコンパ゗ラオプションで契約用コードを
     取り除く。従って実行効率にも影響しない。
     http://ja.wikipedia.org/wiki/契約プログラミング


 契約は取り除かれなければならない
 そのためにはラ゗ブラリだけでは不可能で、コン
  パ゗ル時にバ゗ナリを弄る必要がある
 契約の実現のため、現状はバ゗ナリ改変している
    真に標準搭載されたと言えるのはリラ゗ターがコン
     パ゗ラと統合された時かもね
Code Contractsの構成物
 必須
    Contractクラスなどコードに記述するマーカー
        .NET 4で現状標準搭載されているのはこれだけ
    バ゗ナリリラ゗ター(ccrewrite.exe)


 オプション
    参照ラ゗ブラリ生成(ccrefgen.exe)
    ドキュメント生成(ccdocgen.exe)
    静的チェッカー(cccheck.exe)
        cccheckはPremium Editionのみ
        静的チェックなしの場合は、例外orゕサートを投げる実
         行時チェックという形になる
Get Ready to Contracts
Code Contractsの゗ンストール
 DevLabs:    Code Contracts
  http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx

 Standard     Edition (Visual Studio Professional)
     ccrewrite, ccrefgen, ccdocgen
 Premium      Edition (Visual Studio Premium,Ultimate)
     Standard + cccheck

 Visual
     Studio Express Editionでは使えない
 静的チェッカーの有無も大きなところ
     契約の正しさが実行時じゃないと確認出来ないとい
      うのは、何が正しいのか分からない初学者にとって
      学習が困難になる
プロジェクトのプロパテゖ
       Contractsタブが追加されてる
 に、Code
 チェックボックスをオンにすると各機能が有効に
 パラメータがいっぱいあって困る?
    マニュゕルを見れば勿論、説明がある
    日本語で?zeclさんのスラ゗ドを見よう!
    http://d.hatena.ne.jp/zecl/20110213/p2
事前条件
 Contract.Requires
     無印と<TException>とEndContractBlockの三種
     無印はコンパ゗ラ生成のContractExceptionを投げる
         コンパ゗ラ生成なので型判別したcatchは不可能
     <TE>の場合は指定した例外を投げる
     EndContractBlockはif-then-throwを<TE>に変換する

// これと
if (arg == null) throw new ArgumentNullException("arg");
Contract.EndContractBlock();

// これは大体等しい
Contract.Requires<ArgumentNullException>(arg != null);
事前条件の違い
 EndContractBlockはレガシー環境用
    バ゗ナリリラ゗ターがある環境が前提なら不要
 Assembly   Modeの選択
    Requires, Requires<TE>はStandard Contract
    EndContractBlockを使う場合はCustom Parameter




 無印と<TE>ではリラ゗ト時に残るレベルが違う
    無印の場合はReleaseRequiresでは除去される
 DebugはFull、ReleaseではPreまたはReleaseを推奨
事後・不変・゗ンターフェ゗ス
 事後   : Contract.Ensures
    戻り値を表すContract.Result<T>とセットで使うこと
     が多い

 不変   : Contract.Invariant
    ContractInvariantMethod属性とセットで
    cimコードスニペットを使えば展開される

 ゗ンターフェ゗スへの契約
    書くのがヘンテコで面倒くさい
    cintfコードスニペットを使えば展開される
Marriage with IntelliSense
動かしたけど嬉しさ少なめ?
 静的チェッカなしだと、どうも地味
    Premiumの人なら関係ないですねShit!
 そんな物足りなさを感じるゕナタにVisualな贈り物
 VS拡張:Code    Contracts Editor Extensions
 http://visualstudiogallery.msdn.microsoft.com/85f0aa38
 -a8a8-4811-8b86-e7f0b8d8c71b
 契約がIntelliSenseに表示される!
 FreeなのでVS    Professionalの人でもOK
おや、標準ラ゗ブラリの様子が
 .NET4からBCLも契約済み
    そういう意味では標準搭載と言えなくもない
使い方
 標準ラ゗ブラリは何もしなくても表示される
 自作の契約はReference   Assemblyを作る必要がある




 Reference
      Assemblyはクラスラ゗ブラリなど、契約
 が除去されたリリース用バ゗ナリを参照する他の
 ラ゗ブラリが契約情報を参照したい場合に必要
 (但し、決してリラ゗ト後のバ゗ナリに契約を再
 度埋め込めれるわけではない)
但し制限も色々あり
 コンストラクタは表示されません
 ジェネリックメソッドは表示されません
    Enumerable.Rangeは表示されるのにRepeatは表示さ
     れなかったりしてるのが確認できます
    つまるところLINQのメソッドは全滅
 yieldが含まれると表示されません
 dynamicが含まれると表示されません
 よく落ちます(落ちたらVS再起動まで復活しない)


Editor Extensionsに関してはアルファ版だと思って
暖かく見守りましょう
Merit and Demerit
嬉しいこと1
 引数名を文字列で指定しなくてもいい
     リラ゗ターが埋め込んでくれるから
     コードスニペットcrenは文字列指定付きだけど、個
      人的にはそれは不要だと思う

// この文字列で引数名を書くのがかなり゗ヤだった
if (arg == null) throw new ArgumentNullException("arg");
// それをCode Contractsではこう書き、そしてこれは
Contract.Requires<ArgumentNullException>(arg != null);
// バ゗ナリリラ゗ト後にこうなる
// 最後の"arg != null"がメッセージで、
// 条件を文字列として生成してくれているのが分かる
__ContractsRuntime.Requires<ArgumentNullException>(
    arg != null, null, "arg != null");
嬉しいこと2
 ゗ンターフェ゗スに契約すると、それを実装する
   ものへは何も書かなくても自動で埋め込まれる
// こうして゗ンターフェ゗スへの契約を作ると(cintfスニペット推奨)
[ContractClass(typeof(IHogeContract))]
public partial interface IHoge
{
    void Show(string arg);
}

[ContractClassFor(typeof(IHoge))]
abstract class IHogeContract : IHoge
{
    public void Show(string arg)
    {
        Contract.Requires<ArgumentNullException>(arg != null);
    }
}
それはとっても嬉しいなって
class ClassA : IHoge
{
    // 何も書いていませんが
    // Contract.Requires<ArgumentNullException>(arg != null)が埋めこまれる
    public void Show(string arg)
    {
        Console.WriteLine(arg);
    }
}

class ClassB : IHoge
{
    // 全てのメソッドにif(arg == null) throwを書く時代さようなら!
    public void Show(string arg)
    {
        Console.WriteLine(arg + arg);
    }
}


 これにより、積極的な゗ンターフェ゗スの抽出と
    契約の記述が促されます(不純動機ドリブン)
嬉しいこと3
 静的チェッカーでTester-Doerパターンを安全に

// こんなどうでもいいクラスがあるとして
public class ToaruClass
{
    int value;
    public bool IsReadOnly { get; private set; }

    public void SetValue(int value)
    {
        Contract.Requires(!IsReadOnly);
        this.value = value;
    }
}

var toaru = new ToaruClass();
// IsReadOnlyをチェックしていないのでunproven
toaru.SetValue(100);

// こう書けばSafe
if (!toaru.IsReadOnly) toaru.SetValue(100);
Requiresの基本
 Requiresで検証する要素は外部から見えないと、バ
    ゗ナリリラ゗ターを通りません
public class ToaruClass
{
    int value;
    private bool isReadOnly;

    public ToaruClass(bool isReadOnly)
    {
        this.isReadOnly = isReadOnly;
    }

    public void SetValue(int value)
    {
        // isReadOnlyが外から不可視なのでダメ
        Contract.Requires(!isReadOnly);
        this.value = value;
    }
}
なんでなんで?
 Requires、事前条件はメソッド呼び出し側が、正し
 い呼び出しが可能かの責任を負う必要がある、つ
 まり外から検証可能でないとならない

 逆にEnsures、事後条件が正しく成立するかはメ
 ソッド側の責任なので、メソッド内部できちんと
 Ensuresの条件が満たせる必要がある
Requiresの基本 Part2
 Requires内で使えるメソッドはPureなもののみ
      警告なので実行は出来なくはない
// Pureを付けないと警告が!
[Pure]
public static bool IsNull(string arg)
{
    return arg == null;
}

public void Hoge(string arg)
{
    Contract.Requires(!IsNull(arg));
}

 Pure、つまり副作用ナシということ
      String.IsNullOrEmptyなど当然Pure属性ついてます
      Pureかどうかは自己申告制だったり(非Pureなもので
       も付けること自体は可能、勿論それはダメですよ)
嬉しくないこと
 静的チェッカーは契約の連鎖で成り立っているの
  で、契約されてないラ゗ブラリが混じると警告祭
  りになって鬱陶しい
 そういう場合はContract.Assumeで、契約済みを擬
  態していくのだけど数が多いと心が折れる、だけ
  じゃなくコードが汚れて可読性悪化の一方に
 Typeの一部とかExpressionの一部とか、契約済みの
  はずの標準ラ゗ブラリの中にも上手く動かないの
  がチラホラ
例えばこんなunproven
// これは静的チェッカでunproven行き
var func = typeof(Func<,>);
var genFunc = func.MakeGenericType(typeof(int), typeof(int));




// 警告を元に、こうAssumeすればいいんですがなんというかかんというか
var func = typeof(Func<,>);
Contract.Assume(func.IsGenericTypeDefinition);
Contract.Assume(func.GetGenericArguments().Length == 2);
var genFunc = func.MakeGenericType(typeof(int), typeof(int));
Unproven Hell
// (object x) => (object)((T)x).name
static Func<object, object> CreateGetValue(Type type, string name)
{
    Contract.Requires<ArgumentNullException>(type != null);
    Contract.Requires<ArgumentNullException>(name != null);

    // Expression.Unboxに事後条件非nullの契約がないため
    // Expression.PropertyOrFieldの引数が求めるrequires expr != null の検証に失敗する
    var x = Expression.Parameter(typeof(object), "x");
    var func = Expression.Lambda<Func<object, object>>(
        Expression.Convert(
            Expression.PropertyOrField(
                (type.IsValueType)
                     ? Expression.Unbox(x, type)
                     : Expression.Convert(x, type),
                name),
            typeof(object)),
        x);

    return func.Compile();
}
どういうこと?
 Expressionも基本的には契約されているんですが、
  Expression.UnboxとかExpression.Assignと
  か、.NET4で新しく追加されたものはあまり契約さ
  れてないみたい
 なので山崎春のunproven祭り
 Expressionは基本的に引数に突っ込んで式としてツ
  リー上に組み立てていくものなので、Assumeする
  のが難しい
    もしAssumeするなら、全部バラして変数にしてから
     組み立てなければならないけど、それはない
そして平穏が訪れる
// 面倒くさくて耐え切れない時は静的検証オフ属性をつけてやる
[ContractVerification(false)]
static Func<object, object> Create(Type type, string name)
{
    // (中略)
}


 Contract.Ensures(Contract.Result<T>()          != null); がど
    れだけ大事かが身にしみて分かる
       しかし定型句すぎて面倒くさいのは事実……
       cenコードスニペットがあるとはいえ
Conclusion
その他
 .NET4標準に入っているContractsラ゗ブラリの他に、
 幾つか追加の属性が C:¥Program Files
 (x86)¥Microsoft¥Contracts¥Languages¥CSharp に
 ある(.csフゔ゗ルぽん置き)
     使い方の詳細はマニュゕルに載ってる
 Microsoft
     Researchで開発されている自動パラメタ
 ラ゗ズドテストPexに対してContractsが記述されて
 いると、有効な自動生成パラメータが生成できる
 ようになる
  http://research.microsoft.com/en-us/projects/pex/
まとめ
 メリットを幾つかあげましたが、忘れてはならな
  い基本的なことは、「事前・事後・不変」の契約
  が出来るということ
 でも、堅苦しい理屈だけじゃなく、目で見て分か
  る実用的な便利さを提供してくれるのはいいね!
 if-then-throwを撲滅してくれるというだけでも十
  分嬉しいなって
 まずはそこからで、徐々に高度にステップゕップ
  すればいいんじゃないかな
 Expressで使えないのが痛い&Premium以上でない
  と静的チェッカーが使えないのが大変痛いので、
  将来は何とかして欲しいと切実に願う

基礎からのCode Contracts

  • 1.
    基礎からの Code Contracts @neuecc – 2011/5/23
  • 2.
    Profile  Twitter => @neuecc  Blog => http://neue.cc/  HNは"neuecc" 読むときは“のいえ”で  ドメ゗ン繋いだだけで特に意味はなく発音不能のた め(ccは声に出しにくいのでスルーという適当対応)  Microsoft MVP for Visual C#(2011/4-)  公開してるラ゗ブラリとか  linq.js  DynamicJson  Chaining Assertion  DbExecutor <- (ちょっとだけ)Code Contracts使った
  • 3.
  • 4.
    Code Contracts  .NET4から標準搭載された? mscorlibにSystem.Diagnostics.Contracts  (主に)その中のContractクラスのメソッド群
  • 5.
    何か動かないよ?  よくあるnullチェックをしてみようと思った  Contract.Requiresは事前条件  引数がnullだったら契約違反という感じにしたい static void Hoge(string arg) { Contract.Requires(arg != null); }  が、実行しても無反応  Conditional属性がついているのでコンパ゗ル時に 消える(条件付きメソッド、DEBUGとかでお馴染み)  条件はCONTRACTS_FULL(但し自分で足す意味はない)
  • 6.
    何か動かないよ? Part2  よくあるnullチェックをしてみようと思った again  Contract.Requires<TException>も事前条件  引数がnullだったら契約違反で例外ぶん投げたい static void Hoge(string arg) { Contract.Requires<ArgumentNullException>(arg != null); }  が、変なゕサートが飛ぶ  そしてゕプリは強制終了  リラ゗ターがmustだと?
  • 7.
    つまるところ  Code Contractsの利用にはリラ゗ターが必要 最終的な配布物はコンパ゗ラオプションで契約用コードを 取り除く。従って実行効率にも影響しない。 http://ja.wikipedia.org/wiki/契約プログラミング  契約は取り除かれなければならない  そのためにはラ゗ブラリだけでは不可能で、コン パ゗ル時にバ゗ナリを弄る必要がある  契約の実現のため、現状はバ゗ナリ改変している  真に標準搭載されたと言えるのはリラ゗ターがコン パ゗ラと統合された時かもね
  • 8.
    Code Contractsの構成物  必須  Contractクラスなどコードに記述するマーカー  .NET 4で現状標準搭載されているのはこれだけ  バ゗ナリリラ゗ター(ccrewrite.exe)  オプション  参照ラ゗ブラリ生成(ccrefgen.exe)  ドキュメント生成(ccdocgen.exe)  静的チェッカー(cccheck.exe)  cccheckはPremium Editionのみ  静的チェックなしの場合は、例外orゕサートを投げる実 行時チェックという形になる
  • 9.
    Get Ready toContracts
  • 10.
    Code Contractsの゗ンストール  DevLabs: Code Contracts http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx  Standard Edition (Visual Studio Professional)  ccrewrite, ccrefgen, ccdocgen  Premium Edition (Visual Studio Premium,Ultimate)  Standard + cccheck  Visual Studio Express Editionでは使えない  静的チェッカーの有無も大きなところ  契約の正しさが実行時じゃないと確認出来ないとい うのは、何が正しいのか分からない初学者にとって 学習が困難になる
  • 11.
    プロジェクトのプロパテゖ Contractsタブが追加されてる  に、Code  チェックボックスをオンにすると各機能が有効に  パラメータがいっぱいあって困る?  マニュゕルを見れば勿論、説明がある  日本語で?zeclさんのスラ゗ドを見よう!  http://d.hatena.ne.jp/zecl/20110213/p2
  • 12.
    事前条件  Contract.Requires  無印と<TException>とEndContractBlockの三種  無印はコンパ゗ラ生成のContractExceptionを投げる  コンパ゗ラ生成なので型判別したcatchは不可能  <TE>の場合は指定した例外を投げる  EndContractBlockはif-then-throwを<TE>に変換する // これと if (arg == null) throw new ArgumentNullException("arg"); Contract.EndContractBlock(); // これは大体等しい Contract.Requires<ArgumentNullException>(arg != null);
  • 13.
    事前条件の違い  EndContractBlockはレガシー環境用  バ゗ナリリラ゗ターがある環境が前提なら不要  Assembly Modeの選択  Requires, Requires<TE>はStandard Contract  EndContractBlockを使う場合はCustom Parameter  無印と<TE>ではリラ゗ト時に残るレベルが違う  無印の場合はReleaseRequiresでは除去される  DebugはFull、ReleaseではPreまたはReleaseを推奨
  • 14.
    事後・不変・゗ンターフェ゗ス  事後 : Contract.Ensures  戻り値を表すContract.Result<T>とセットで使うこと が多い  不変 : Contract.Invariant  ContractInvariantMethod属性とセットで  cimコードスニペットを使えば展開される  ゗ンターフェ゗スへの契約  書くのがヘンテコで面倒くさい  cintfコードスニペットを使えば展開される
  • 15.
  • 16.
    動かしたけど嬉しさ少なめ?  静的チェッカなしだと、どうも地味  Premiumの人なら関係ないですねShit!  そんな物足りなさを感じるゕナタにVisualな贈り物  VS拡張:Code Contracts Editor Extensions http://visualstudiogallery.msdn.microsoft.com/85f0aa38 -a8a8-4811-8b86-e7f0b8d8c71b  契約がIntelliSenseに表示される!  FreeなのでVS Professionalの人でもOK
  • 17.
    おや、標準ラ゗ブラリの様子が  .NET4からBCLも契約済み  そういう意味では標準搭載と言えなくもない
  • 18.
    使い方  標準ラ゗ブラリは何もしなくても表示される  自作の契約はReference Assemblyを作る必要がある  Reference Assemblyはクラスラ゗ブラリなど、契約 が除去されたリリース用バ゗ナリを参照する他の ラ゗ブラリが契約情報を参照したい場合に必要 (但し、決してリラ゗ト後のバ゗ナリに契約を再 度埋め込めれるわけではない)
  • 19.
    但し制限も色々あり  コンストラクタは表示されません  ジェネリックメソッドは表示されません  Enumerable.Rangeは表示されるのにRepeatは表示さ れなかったりしてるのが確認できます  つまるところLINQのメソッドは全滅  yieldが含まれると表示されません  dynamicが含まれると表示されません  よく落ちます(落ちたらVS再起動まで復活しない) Editor Extensionsに関してはアルファ版だと思って 暖かく見守りましょう
  • 20.
  • 21.
    嬉しいこと1  引数名を文字列で指定しなくてもいい  リラ゗ターが埋め込んでくれるから  コードスニペットcrenは文字列指定付きだけど、個 人的にはそれは不要だと思う // この文字列で引数名を書くのがかなり゗ヤだった if (arg == null) throw new ArgumentNullException("arg"); // それをCode Contractsではこう書き、そしてこれは Contract.Requires<ArgumentNullException>(arg != null); // バ゗ナリリラ゗ト後にこうなる // 最後の"arg != null"がメッセージで、 // 条件を文字列として生成してくれているのが分かる __ContractsRuntime.Requires<ArgumentNullException>( arg != null, null, "arg != null");
  • 22.
    嬉しいこと2  ゗ンターフェ゗スに契約すると、それを実装する ものへは何も書かなくても自動で埋め込まれる // こうして゗ンターフェ゗スへの契約を作ると(cintfスニペット推奨) [ContractClass(typeof(IHogeContract))] public partial interface IHoge { void Show(string arg); } [ContractClassFor(typeof(IHoge))] abstract class IHogeContract : IHoge { public void Show(string arg) { Contract.Requires<ArgumentNullException>(arg != null); } }
  • 23.
    それはとっても嬉しいなって class ClassA :IHoge { // 何も書いていませんが // Contract.Requires<ArgumentNullException>(arg != null)が埋めこまれる public void Show(string arg) { Console.WriteLine(arg); } } class ClassB : IHoge { // 全てのメソッドにif(arg == null) throwを書く時代さようなら! public void Show(string arg) { Console.WriteLine(arg + arg); } }  これにより、積極的な゗ンターフェ゗スの抽出と 契約の記述が促されます(不純動機ドリブン)
  • 24.
    嬉しいこと3  静的チェッカーでTester-Doerパターンを安全に // こんなどうでもいいクラスがあるとして publicclass ToaruClass { int value; public bool IsReadOnly { get; private set; } public void SetValue(int value) { Contract.Requires(!IsReadOnly); this.value = value; } } var toaru = new ToaruClass(); // IsReadOnlyをチェックしていないのでunproven toaru.SetValue(100); // こう書けばSafe if (!toaru.IsReadOnly) toaru.SetValue(100);
  • 25.
    Requiresの基本  Requiresで検証する要素は外部から見えないと、バ ゗ナリリラ゗ターを通りません public class ToaruClass { int value; private bool isReadOnly; public ToaruClass(bool isReadOnly) { this.isReadOnly = isReadOnly; } public void SetValue(int value) { // isReadOnlyが外から不可視なのでダメ Contract.Requires(!isReadOnly); this.value = value; } }
  • 26.
    なんでなんで?  Requires、事前条件はメソッド呼び出し側が、正し い呼び出しが可能かの責任を負う必要がある、つ まり外から検証可能でないとならない  逆にEnsures、事後条件が正しく成立するかはメ ソッド側の責任なので、メソッド内部できちんと Ensuresの条件が満たせる必要がある
  • 27.
    Requiresの基本 Part2  Requires内で使えるメソッドはPureなもののみ  警告なので実行は出来なくはない // Pureを付けないと警告が! [Pure] public static bool IsNull(string arg) { return arg == null; } public void Hoge(string arg) { Contract.Requires(!IsNull(arg)); }  Pure、つまり副作用ナシということ  String.IsNullOrEmptyなど当然Pure属性ついてます  Pureかどうかは自己申告制だったり(非Pureなもので も付けること自体は可能、勿論それはダメですよ)
  • 28.
    嬉しくないこと  静的チェッカーは契約の連鎖で成り立っているの で、契約されてないラ゗ブラリが混じると警告祭 りになって鬱陶しい  そういう場合はContract.Assumeで、契約済みを擬 態していくのだけど数が多いと心が折れる、だけ じゃなくコードが汚れて可読性悪化の一方に  Typeの一部とかExpressionの一部とか、契約済みの はずの標準ラ゗ブラリの中にも上手く動かないの がチラホラ
  • 29.
    例えばこんなunproven // これは静的チェッカでunproven行き var func= typeof(Func<,>); var genFunc = func.MakeGenericType(typeof(int), typeof(int)); // 警告を元に、こうAssumeすればいいんですがなんというかかんというか var func = typeof(Func<,>); Contract.Assume(func.IsGenericTypeDefinition); Contract.Assume(func.GetGenericArguments().Length == 2); var genFunc = func.MakeGenericType(typeof(int), typeof(int));
  • 30.
    Unproven Hell // (objectx) => (object)((T)x).name static Func<object, object> CreateGetValue(Type type, string name) { Contract.Requires<ArgumentNullException>(type != null); Contract.Requires<ArgumentNullException>(name != null); // Expression.Unboxに事後条件非nullの契約がないため // Expression.PropertyOrFieldの引数が求めるrequires expr != null の検証に失敗する var x = Expression.Parameter(typeof(object), "x"); var func = Expression.Lambda<Func<object, object>>( Expression.Convert( Expression.PropertyOrField( (type.IsValueType) ? Expression.Unbox(x, type) : Expression.Convert(x, type), name), typeof(object)), x); return func.Compile(); }
  • 31.
    どういうこと?  Expressionも基本的には契約されているんですが、 Expression.UnboxとかExpression.Assignと か、.NET4で新しく追加されたものはあまり契約さ れてないみたい  なので山崎春のunproven祭り  Expressionは基本的に引数に突っ込んで式としてツ リー上に組み立てていくものなので、Assumeする のが難しい  もしAssumeするなら、全部バラして変数にしてから 組み立てなければならないけど、それはない
  • 32.
    そして平穏が訪れる // 面倒くさくて耐え切れない時は静的検証オフ属性をつけてやる [ContractVerification(false)] static Func<object,object> Create(Type type, string name) { // (中略) }  Contract.Ensures(Contract.Result<T>() != null); がど れだけ大事かが身にしみて分かる  しかし定型句すぎて面倒くさいのは事実……  cenコードスニペットがあるとはいえ
  • 33.
  • 34.
    その他  .NET4標準に入っているContractsラ゗ブラリの他に、 幾つか追加の属性がC:¥Program Files (x86)¥Microsoft¥Contracts¥Languages¥CSharp に ある(.csフゔ゗ルぽん置き)  使い方の詳細はマニュゕルに載ってる  Microsoft Researchで開発されている自動パラメタ ラ゗ズドテストPexに対してContractsが記述されて いると、有効な自動生成パラメータが生成できる ようになる http://research.microsoft.com/en-us/projects/pex/
  • 35.
    まとめ  メリットを幾つかあげましたが、忘れてはならな い基本的なことは、「事前・事後・不変」の契約 が出来るということ  でも、堅苦しい理屈だけじゃなく、目で見て分か る実用的な便利さを提供してくれるのはいいね!  if-then-throwを撲滅してくれるというだけでも十 分嬉しいなって  まずはそこからで、徐々に高度にステップゕップ すればいいんじゃないかな  Expressで使えないのが痛い&Premium以上でない と静的チェッカーが使えないのが大変痛いので、 将来は何とかして欲しいと切実に願う