- インターセプター(OnCreation、EnrichWith)
- ジェネリック型
- 属性(DefaultConstructor、ValidationMethod、その他すべて)
- テストについて少し
インターセプター
バージョン2.5以降では、新しく作成されたオブジェクトを後処理したり、完全に置き換えたりする可能性があります。 この場合、目標はまだ別のAOPフレームワークを作成することではありません。すでに十分な数のAOPフレームワークが存在するため、人生を楽にすることができます。
後処理には次の2つの方法があります。
- OnCreation-パラメーターとしてアクションを取り、オブジェクトの(カスタム)初期化を実行できます。 SturctureMapコンテキストにアクセスできます。
- EnrichWith-Functionをパラメーターとして使用します。 要求されたものと互換性のある型を返すことができます。
- 独自のインターセプター
正直なところ、簡単な例では、EnrichWithとその逆のOnCreationの使用の違いと利点を伝えることはあまり良くありません。
オンクリエーション
デモンストレーションには、次の単純なクラスを使用できます。
public class ClassS : IClassS { public int Counter { get; private set; } public void Init() { Counter = -100; } public void Init(IClass1 class1) { Counter = -50; } public void Increase() { Counter++; } }
これで、 OnCreationメソッドの使用方法を示すことができます。
public class InterceptionsSimple { public IContainer Container; public InterceptionsSimple() { Container = new Container(x => x.For<IClassS>() .Use<ClassS>() .OnCreation(c => c.Init())); } }
IoCフレームワークからクラスを取得すると、Counterの値が-100であることがわかります。 ご覧のとおり、アプリケーションではすべてが非常にシンプルであり、コードが何をするかを直感的に明確にしています。 訓練を受けていない人は、StructureMapのクラス定義を読み、何がどのように起こっているかをすぐに理解できます。
また、StructureMap自体によって構築されたオブジェクトを初期化メソッドに渡す必要がある可能性もあります。 これらの目的のために、同じオーバーロードメソッドを使用します。
public class InterceptionWithContext { public IContainer Container; public InterceptionWithContext() { Container = new Container(x => { x.For<IClass1>().Use<Class1>(); x.For<IClassS>().Use<ClassS>() .OnCreation((context, cls) => { var class1 = context.GetInstance<IClass1>(); cls.Init(class1); }); }); } }
この場合、ラムダ式はコンテナ自体にアクセスでき、構造がStructureMapに割り当てられているオブジェクトを取得できます。
エンリッチウィズ
このメソッドを使用すると、型変換が可能な場合、構築されたクラスを別のクラスにラップできます。 たとえば、クラスがあるとします
public class ClassSs : ClassS { private readonly ClassS s; public int Abs { get { return Math.Abs(s.Counter); } } public ClassSs(ClassS s) { this.s = s; } }
その後、次のコードを使用して、StructureMapから取得できます。
public class InterceptionWithContext2 { public IContainer Container; public InterceptionWithContext2() { Container = new Container(x => { x.For<IClass1>().Use<Class1>(); x.For<IClassS>().Use<ClassS>() .EnrichWith(cls => { cls.Init(); return new ClassSs(cls); }); }); } }
その結果、IClassSインターフェイスを実装するクラスのインスタンスを取得しようとすると、ClassSsクラスが取得されます。
ジェネリック型
テンプレートタイプがないと、多かれ少なかれ大規模なプログラムを想像することはおそらくすでに困難です。したがって、このトピックはStructureMapを検討する文脈では小さいことが判明しますが、それは重要です。
したがって、テンプレートアダプタがあるとします。
public interface IAdapter { string SomeMethod(); } public interface IAdapter<T> : IAdapter {} public class Adapter<T> : IAdapter<T> { public string SomeMethod() { return typeof (T).ToString(); } }
特定のタイプの相続人もいます。
public class StringAdapter : Adapter<string> {} public class IntAdapter : Adapter<int> {}
アダプターのTのタイプに制限はありません。
テンプレートタイプを操作する方法はいくつかあります。 最も簡単な方法は、特定のタイプのStringAdapter、IntAdapterを登録して呼び出すことです。
public class GenericTypes { public IContainer Container; public GenericTypes() { Container = new Container(x => { x.For(typeof (IAdapter<>)).Use(typeof (StringAdapter)); x.For<IAdapter<int>>().Use<IntAdapter>(); }); } }
この例は、テンプレートクラスを登録するための2つの同一のメソッドを示しています。
いくつかの方法でそれらを呼び出すことができます。
方法1:特定のタイプのアダプターを提供するようにコンテナーに依頼できます。
private static string GenericTypesExample() { var container = new GenericTypes().Container; var stringAdapter = container.GetInstance<StringAdapter>(); var intAdapter = container.GetInstance<IntAdapter>(); return stringAdapter.SomeMethod() + " " + intAdapter.SomeMethod(); }
2番目の方法はより一般的であり、私の意見では、実際により適用可能です。 2番目の方法を使用すると、StrutureMapが必要なクラスを返すことができるキーのタイプ(T)を渡すことができます。
コンテナの構成は同じままで、準備方法が変わります。
private static string GenericTypesExample() { var container = new GenericTypes().Container; var instance = container .ForGenericType(typeof (IAdapter<>)) .WithParameters(typeof(string)) .GetInstanceAs<IAdapter>(); return instance.SomeMethod(); }
つまり そのような型に対してテンプレート型が必要であることをコンテナに通知し、IAdapter型としてインスタンスを返します。
実際の使用では、次のようになります。
private static string GenericTypesExample<T>() { var container = new GenericTypes().Container; var instance = container .ForGenericType(typeof (IAdapter<>)) .WithParameters(typeof(T)) .GetInstanceAs<IAdapter>(); return instance.SomeMethod(); }
特定のアダプターは、パラメーターTのタイプによって決まります。
属性
StructureMapは、属性を使用してある程度構成できます。 DefaultCounstructor属性は既に強調表示されています。これは、デフォルトで使用されるコンストラクタを示しています。 登録用のクラスとインターフェイスを指定するための属性があり、クラスプロパティは自動的に入力され、検証のためのメソッドを設定します。
作成者自身が属性に夢中にならないことをお勧めします。属性は高度に専門化されており、基本的な構成のみを許可し、プロジェクト全体に散在しているため、サポートが困難です。 すべてを1か所で宣言する方が適切です。
最も有用な属性はすでに指定されており、次に有用なのはValidationMethodで、残りはお勧めしませんが、本当に必要な場合は、ここに簡単な説明があります。
ValidationMethod
クラスの自己テストに使用されます。 つまり クラスを作成し、クラスの作成の正確さを決定するメソッドを作成できます。 StructureMapはそれを選択し、自己テスト用に実行できます。 これは、問題のフレームワークの一般的にユニークな機能のようです。
特定のプロパティを設定する必要があるクラスがあるとします。 データベース接続文字列、相互作用設定、複雑な通信が可能です。 この例では、フィールドが空であってはならないという事実だけに制限します。
public class SelfValidation { public string Name { get; set; } [ValidationMethod] public void IsClassBuildCorrectly() { if(string.IsNullOrWhiteSpace(Name)) throw new ArgumentException("Name can't be null or empty"); } }
メソッドがValidationMethodとしてマークされていることがわかります。 一般に、このようなメソッドは複数存在する可能性があり、StructureMapはそれらすべてをスキャンし、 AssertConfigurationIsValidメソッドを呼び出すときに1つずつ実行しようとします。 大規模な構成では、フレームワークはすべての依存関係を構築し、すべてのフィールドに入力し、問題の属性でマークされたすべてのメソッドを実行しようとするため、このメソッドに注意してください。
クラスを次のように登録します。
public class ValidationShowcase { public IContainer Container; public ValidationShowcase() { Container = new Container(x => x.ForConcreteType<SelfValidation>()); } }
これで、コンテナから取得することができます。
private static string ValidationShowcaseExample() { var container = new ValidationShowcase().Container; container.AssertConfigurationIsValid(); return ""; }
上記のメソッドを呼び出すと、StructureMapConfigurationExceptionが発生し、StructureMap内部デバイスのチェックによって引き起こされる内部例外が表示されます。
スクリーンショットは、例外的な状況に関するメッセージで、メッセージが正確に表示されることを示しています。
PluginFamily
タグ付きタイプがプラグインタイプとして使用されることをStructureMapに通知します。 あたかも私たちが書いたかのように。 < プラグイン タイプ >の場合 。
デフォルトで返されるタイプを指定することもできます。また、シングルトンになることを具体的に示すこともできます。
[PluginFamily("Default", IsSingleton = true)]
プラグ可能
マークされたタイプはプラグインのコレクションに含まれ、特定の実装を示します。 を使用するのと同等です。 < プラグ可能な タイプ >を 使用します。 タイプには常に名前を使用する必要があります。
[Pluggable("Default")]
セッタープロパティ
属性でマークされたプロパティをフレームワークを使用して初期化する必要があることを示します。 これらは必須であり、StructureMapがそれらを初期化できない場合、ランタイムエラーが発生します。
テスト
StructureMapは、すべてのクラス、パラメーター、およびその他のコンポーネントの正しい定義について、StructureMap自体をチェックできるという事実に加えて、登録済みクラスのチェックを正確に行うこともできます。 フレームワークにはテストツールが組み込まれているため、車輪を再発明したり、美しく簡潔にテストを書いたりする必要はありません。
StructureMapにはRhinoMockおよびMoqフレームワークが組み込まれています。 それらを使用するには、NuGet structuremap.automockingパッケージを提供する必要があります。その後、オブジェクトの非表示を使用できます。
MoqとRhinoMockのレビューは、この記事の範囲外です。
おわりに
StructureMapをより詳細に、そして実際に研究したいという願望があることを願っています。 また、プロジェクトのソースコードを確認することをお勧めします。興味深い有益なアイデアを見つけることができます。
構成ファイルに基づいたコンテナーの作成に関する記事をオーバーボードします。 ネストされたコンテナとそれらが必要な理由を操作します。 近い将来、このギャップが埋められることを願っています。
最初の部分では、トピックについて説明しました。
- 設置
- 登録(基本、プロファイル、プラグイン、スキャン、展開)
2番目の部分では、以下について説明します。
- コンストラクター(単純型、デフォルトのコンストラクター、複合型、強制、引数の設定)
- プロパティ(単純なプロパティ設定、ビルトインプロパティ設定、フレームワークを使用したプロパティの設定、既存のクラスの拡張)
- ライフタイム