ViewModel とかいちいち書いてられないよね
こんな DSL 書ければいいのに(願望)。
書きたいDSL
http://ufcpp.net/study/csharp/draft/Characteristics.txt
module TypeDefinition.Models { // 特性データ type Characteristics requres Norm >= 1 { // 特性 X X : double requires 0 <= X && X <= 1; // 特性 Y Y : double requires 0 <= Y && Y <= 1; // 特性 Z Z : double requires 0 <= Z && Z <= 1; // 一次ノルム Norm = X + Y + Z; // 変更の適用操作 command Submit excuted on this.Valid; } }
ちょっと恣意的な型なのでわかりにくいですが、以下のようなもの:
- 元データとして X, Y, Z の3つの double を持ってる
- そこから導出される値として Norm を計算できる
- X, Y, Z はいずれも 0~1 という制約付き
- さらに、Norm が1以上という制約も付いてる
- (ViewModel 上で使う用に)Submit というコマンドを持っていて、こいつはデータがきちんと制約を満たしていないと実行できない
生成したいコード
こいつからこんなソース吐き出したいなぁ(願望)
注意: 適当なので、いまいちな部分も結構あります(Contracts の使い方わかってなかったり、Submit コマンドの扱い方に迷いがあったり)
- http://ufcpp.net/study/csharp/draft/Characteristics.cs
- immutable で、かつ、コンストラクター内でデータ検証
- なので、コンストラクターさえ通ればデータの有効性保証
- (追記)色々突っ込みを受けて微修正
- partial 付けた代わりに、プロパティの private set やめて、private readonly なバックフィールドを追加
- Contract.Assert じゃなくてこの場合 Contract.Ensures だった
- http://ufcpp.net/study/csharp/draft/CharacteristicsViewModel.cs
- ViewModel 用(この例は Silverlight)
- INotifyPropertyChanged.PropertyChanged 地獄
- Norm = X + Y + Z みたいな記述から、プロパティの依存関係を見て、PropertyChanged の呼び出しを自動的に追加
- ICommand.CanExecuteChanged 地獄
- INotifyDataErrorInfo 地獄
- (http://ufcpp.net/study/csharp/draft/DelegateCommand.cs)
あとは OR マッパー向けのエンティティクラス作ったりかな。階層的なデータとかコレクションも扱えると完璧だけども、結構めんどくさそう。
この DSL のポイント
- GUI 用の ViewModel でも、データアクセス用の Entity でも、大体共通して書くのは:
- プロパティ名、型、データ検証属性
- あと、DSL 中の注釈もそのまま DisplayName 属性とか ///<summary> コメントに反映されて欲しい
- 生成したいのは
- ViewModel 用
- ユーザーからの入力をいったんなんでも受けた上で、データ検証通らないと Submit コマンド実行できないように
- その他用
- GUI が絡む部分以外はいっそ immutalbe にしておく方が人的ミスも減るし、最適化もかけやすいはず
- one-phase 構築して(コンストラクターで一気に初期化して、以後、個別のプロパティ変更を認めない)、データ検証通らない状態を認めない
- 元データ以外に、導出される値があるはず
- ViewModel にする場合には、X の変更を Norm の変更としても PropertyChanged イベント起こさないとダメ
- 変更の通知はプロパティ間の依存だけじゃなくて、コマンドの実行可否にも影響するので、ICommand.CanExecuteChanged イベントも必要
- 複数のデータにまたがるデータ検証もある
- 例えば今回の場合、ViewModel 用なら Submit の CanExcute で検証するし、その他用ならコンストラクターで
DSL 作成支援、もっと欲しい
まあ、パーサー書いてコード生成すりゃできるんでしょうけども、数日前に書いたように、単に頑張ってパース&ソースコード生成できてもいまいちだなぁと思っておりまして:
- 構文ハイライト欲しい
- IntelliSense 欲しい
- 式を書ける部分にはまんま C# の文法使いたい
- 自分で C# のパーサー書かなくても、自作部分から
syntax View = Identifier ‘=’ CSharp.Expression;
みたいに書けば標準で用意されてる構文定義使ってパースできるような。
- 自分で C# のパーサー書かなくても、自作部分から
- コード生成の方も、文字ベースのテンプレートじゃなくて、構文木ベースでできないものか
- それも、関数型言語に見られるような Quote 的に、普通に C# っぽい記述書けば構文木になるような(今の式木 ラムダの拡張)
そういうのができる仕組みとか整わないかなぁ・・・
コメントを残す