Your SlideShare is downloading. ×
0
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
基礎からのCode Contracts
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

基礎からのCode Contracts

12,361

Published on

C#ユーザー会セッション資料

C#ユーザー会セッション資料

Published in: Technology
0 Comments
14 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
12,361
On Slideshare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
45
Comments
0
Likes
14
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 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. First Step
  • 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 to Contracts
  • 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. Marriage with IntelliSense
  • 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. Merit and Demerit
  • 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パターンを安全に// こんなどうでもいいクラスがあるとして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をチェックしていないのでunproventoaru.SetValue(100);// こう書けばSafeif (!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// (object x) => (object)((T)x).namestatic 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. Conclusion
  • 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以上でない と静的チェッカーが使えないのが大変痛いので、 将来は何とかして欲しいと切実に願う

×