DDDProjector - Home
フレームワークと言っても、クラスライブラリとしてではなく、C# ソリューション (を作成するツール) として提供します。なので、フレームワークのソースコードを直接カスタマイズすることが可能です。
サンプルアプリではデータストアに SQL CE 4.0、プレゼンテーション技術に Windows フォームを使用していましたが、このフレームワークでは特定のデータストア・プレゼンテーション技術には依存していません。
ツールを起動すると、ソリューション名や各プロジェクト名・名前空間の入力フォームが表示されます。
各フィールドを入力後、作成ボタンを押すと保存先選択ダイアログが出てきます。保存先を決定するとそこにソリューションが作成されます。
なお、入力値の妥当性検証は一切行っていないので注意してください。
これから少しずつ解説記事を公開していこうと思います。
Sandcastle で作った、アプリケーションアーキテクチャに関する説明ドキュメントも同梱してあります。
# ユニットテストは用意していません。
DDD サンプル - ToDoList - Home
- 列挙型のプロパティをマッピングできない
- クエリー式で、列挙値が扱えない (int として扱わなければいけない)
- クエリー式で、エンティティを直接比較できない (主キー等のプロパティを比較しなければいけない)
- コレクションの順序を保存できない (順序を自分で管理する必要がある)
- 関連オブジェクトの読み込みが非透過的
- 関連オブジェクトの遅延読み込みが使いづらい (コレクションだけ遅延読み込みにするとかできない。そのためプロキシ作成を容認しなければいけない)
- NHibernate の cascade=all-delete-orphan に相当する機能がない (集約内の子エンティティの削除はパーシステンスレイヤへ明示的に指示せずにできるべき)
Entity Framework 4.1 は試してないけど、この辺はそのままっぽい感じ
2番目のはロジックで弾きだした値を列挙型で扱おうとしてダメだった
最後のだけは何とかならんものか…
ファクトリだと、集約ルートの生成とそれ以外のエンティティの生成はアトミックに扱えないけどビルダならアトミックに扱えますし、構築中は不正な状態も扱えます。
また、構築に関するロジックがエンティティに一切なくなります。
ビルダは特に、UI への入力直後に入力チェックする場合や、ウィザード形式で入力を進めていく場合なんかに本領発揮します。
Person.cs
public sealed partial class Person
{
private Person(string name, IList<Address> addresses)
{
_name = name;
_addresses = addresses;
}
private string _name;
private readonly IList<Address> _addresses;
public string Name
{
get { return _name; }
}
public IEnumerable<Address> Addresses
{
get { return _addresses; }
}
}
Address.cs
public sealed class partial Address
{
...
}
Person.Builder.cs
partial class Person
{
public sealed class Builder
{
[Flags]
public enum States
{
Valid = 0,
NameIsEmpty = 1,
NameIsTooLong = 2,
AddressListIsEmpty = 4,
AddressListHasError = 8,
}
public static readonly int MaxNameLength = 20;
public Builder()
{
Name = null;
AddressBuilders = new List<Address.Builder>();
}
public Builder(Person target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
Name = target.Name;
AddressBuilders = target._addresses.Select(address => new Address.Builder(address)).ToList();
}
private readonly Person _target;
public string Name;
public readonly List<Address.Builder> AddressBuilders;
public Address.Builder AddAddress()
{
var addressBuilder = new Address.Builder();
AddressBuilders.Add(addressBuilder);
return addressBuilder;
}
public void RemoveAddress(int index)
{
AddressBuilders.RemoveAt(index);
}
public States Validate()
{
return (ValidateName() | ValidateAddresses());
}
public States ValidateName()
{
if (string.IsNullOrWhitespace(Name))
{
return States.NameIsEmpty;
}
if (MaxNameLength < Name.Length)
{
return States.NameIsTooLong;
}
return States.Valid;
}
public States ValidateAddresses()
{
States result = States.Valid;
if (AddressBuilders.Length == 0)
{
result |= States.AddressListIsEmpty;
}
foreach (var addressBuilder in AddressBuilders)
{
if (addressBuilder.Validate() != Address.Builder.States.Valid)
{
result |= States.AddressListHasError;
break;
}
}
return result;
}
public Person Build()
{
if (Validate() != States.Valid)
{
throw new InvalidOperationException();
}
var addresses = AddressBuilders.Select(builder => builder.Build()).ToList();
if (_target == null)
{
return new Person(Name, addresses);
}
else
{
_target._name = Name;
_target._addresses.Clear();
foreach (var address in addresses)
{
_target._addresses.Add(address);
}
return _target;
}
}
}
}
Address.Builder.cs
partial class Address
{
public sealed class Builder
{
[Flags]
public enum States
{
...
}
internal AddressBuilder() { ... }
public States Validate() { ... }
internal Address Build() { ... }
}
}
まだ色々思案中でこれが本当に良い案なのかどうか確信は持ててないのですが。。。
[関連書籍]
ついにエリック・エヴァンスの "Domain-Driven Design" の日本語版が出版されますよ
C#と諸々 ローカル変数に参照渡し
ローカル変数に参照渡しはできないけれど、参照を扱うことはできるということに気付きました。
実は C# には隠しキーワードがいくつかあって、その内の __makeref と __refvalue を使うことで参照を扱うことができます。
using System;
class Program
{
static void Main()
{
int v0 = 0;
TypedReference r0 = __makeref(v0);
__refvalue(r0, int) = 5;
Console.WriteLine(v0); //=> 5
}
}
SpecialNameAttribute クラス (System.Runtime.CompilerServices)
最近見っけた。
これ使うとメソッドやフィールドに IL レベルで specialname 修飾子を付けれる。
using System;
using System.Runtime.CompilerServices;
class Hoge
{
public Hoge(string value)
{
_value = value;
}
private string _value;
[SpecialName]
public static string op_Explicit(Hoge obj)
{
return obj._value;
}
}
こうすれば普通のメソッド定義と同じ形式で演算子のオーバーロードができる。
けど、同一プロジェクト内からは演算子として呼び出すことはできなくて、静的メソッドとして呼び出す必要あり。
これを使って何か面白いことできないかなーとか考えてたんだけど・・・無い!
.ctor なんて名前のメソッドは定義できないからコンストラクタは作れないし、get_XXX とか set_XXX とか add_XXX とか remove_XXX なんてメソッド作ったところでプロパティやイベントになるわけでもなし。まぁできたところで・・・何も面白くない。
interface との変換演算子とかジェネリックな変換演算子なんて作ってみたけどコンパイラが認識しないから実行されず。
強いて言えば C++/CLI で使える非静的な演算子を用意したりできるけど・・・無意味すぎ。
struct Hoge
{
public void Clear()
{
this = new Hoge();
}
}
ちょっと驚きましたが、よくよく考えると出来て当然ですね。
Java/.NETアーキテクトを見分ける10の質問 ( by @yfakariya ) - 猫とC#について書くmatarilloの日記
おかしなところあったら誰か突っ込みお願いします。。。
1. try-catch-finally が try-catch および try-finally について不適切である理由を述べよ(try-catch-finally のほうが多くの場合適切であると思う場合はその理由を述べよ)
どれが適切かはケースバイケース。
try-catch のスコープはできるだけ狭くすることが推奨されるため、それに従うと try-catch-finally よりも、try-finally の中に try-catch がネストされることが多くなる。が、個人的にはキャッチ対象の例外が他にスローされる可能性がないのならば、スコープを広げて try-catch-finally を使用しても良いと考える。
2. Unicode で制御文字を検出する正規表現を記述せよ。
[^\d\w\s]
自信がなかったので PowerShell で検証したけど問題なさそうかな。。。
3. UTC 時刻とローカル時刻のメリットとデメリットについて説明せよ。
UTC 時刻はロケール非依存のため世界共通で使用できるが、直観的ではない。
ローカル時刻は直観的であるが、ロケール依存のため世界共通で使用できない。
4. 基底クラスとインターフェイスの使い分けについて述べよ。ただし、セマンティクスとバージョニングの観点は必ず含めること。
ユーザーが実装するべき型に対して、概念的に汎化しているのならば基底クラス。
ユーザーが実装するべき型に対して、規約を表すのならばインターフェイス。
バージョニングってのは、、、基底クラスならば型を拡張する際に仮想メソッドとすることでユーザー側の対応を必須にせずに済む、ってことかな…?使い分けの基準にはしないなぁ。。。
5. Windows NT と Linux それぞれにおいて、ファイルのアップロードプログラムのセキュリティのためのアクセス権およびユーザー権限の設定について述べよ。
次のような要件を想定。
・アプリケーション形態:Web Application (イントラネット)
・認証方式:Windows 認証
・ファイルの格納方法:ファイルシステム
・アップロード許可範囲:限られたユーザーのみ
この場合、グループを作成し、そのグループに対して Write のアクセス権を付加。アップロードを許可するユーザーはそのグループに所属させる。
Linux はさっぱり。
6. 分散環境における同期呼び出しと非同期呼び出しについて、それぞれの利点と欠点を上げ、比較せよ。
同期呼び出しはシンプルに処理できるが、処理中の空きリソースが無駄。
非同期呼び出しはリソースを有効的に使用できるが、結果を受け取る必要がある場合は処理が複雑になりがち。
7. Web AP のスケーラビリティを向上させるための方法を 3 つ以上上げよ。必要であればまだ未リリースの技術を使用しても構わない。
・ロードバランサー
・Key-Value ストア
・分散処理フレームワーク
8. TCP/IP プロトコル上で WS-Reliable Messaging を採用する意義を述べよ。
TCP/IP はプロトコルレベルでは信頼性を保証しないけれど、WS-Reliable Messaging を採用することで信頼性を保証できるようになる。
9. MVC パターンの目的、メリット、デメリットを述べよ。
テスト容易性や保守性が向上する。
MVC パターンを想定して作られていない高機能 UI コントロールとの相性が悪い場合がある。
10. レイヤーアーキテクチャの欠点と適用すべきでない事例をあげよ。
レイヤーアーキテクチャをドメインモデル主体の3層構造として。
欠点としては、仕様として扱うデータの種類が増えた場合、全レイヤーに影響が出る。
適用すべきでない事例は、ドメインロジックをほぼ持たず、画面上の項目とデータベース上の項目がほぼ一致する単純なデータ管理システム等には適用すべきではない。
「C#できます」と言い放ったあいつがJavaプログラマであることを見分ける10の質問 - 猫とC#について書くmatarilloの日記
仕事で C# 使わなくなって久しい僕なので、あまり自信ないけど…。
* ==演算子のオーバーロードを実装してEqualsメソッドと同じ処理を実行するようにしてもよい場合はどのような時か?
同値であるオブジェクトを同一であるとして扱う場合。
* ループ内でなければ、たとえ100個の文字列型変数であってもまとめて+演算子で連結してよい理由を説明せよ。
+演算子が99回繰り返されるのではなく100個の文字列を一つにまとめるという処理に最適化されるため。
* List<int>のように値型を格納するジェネリックコレクションを使ってもボックス化/ボックス化解除が発生しない理由を説明せよ。
実行時に、要素の型が内部的にも object 型ではなく実際のジェネリック引数の型で置換されて動作するため。
* Full GC(Gen2 GC)が動作したときに断片化していてもコンパクションされないヒープ領域はどのような領域か?
ラージオブジェクトヒープと呼ばれる、一定サイズ以上のサイズを持ったオブジェクトが配置される領域。
* throw; とthrow ex; の違いをスタックトレースの観点で説明せよ。
前者は catch するまでのスタックトレースを維持するが、後者はその時点からのスタックトレースで上書きされる。
* フィールドのアクセス修飾子をprivateにしプロパティのgetter/setterではそのフィールドを読み書きするだけというコードが馬鹿馬鹿しい理由を説明せよ。
プロパティで単一フィールドの読み書き以外を行わない場合、自動プロパティが使用できるため。
* nullを参照している参照型変数のメソッドを呼び出そうとした場合でもNullReferenceExceptionが発生しないのは主にどういう状況か?
第一引数が null であっても NullReferenceException が発生しない拡張メソッドである場合。
* クラスと構造体の違いは何か?(「スタックとヒープ」以外で)
全部「スタックとヒープ」に起因するけど、次のような違いがある。(スタックとヒープに起因しないものあるっけ?)
・継承できない
・ユーザー定義のデフォルトコンストラクタとファイナライザを用意できない
・== 演算子、!= 演算子がデフォルトでは用意されていない
・object や interface にキャストするとボックス化が生じる
* デストラクタとは何か?
オブジェクトが破棄される際に呼び出される特殊なメソッド。C# ではファイナライザと呼ぶ。
* インターフェースの明示的実装を利用する目的を1つ説明せよ。
対象のインターフェイスを意識していないコードから無闇に呼び出せないように隠蔽する。