.NET Framework 4.5 Developer Preview の新機能に関する言及
リフレクション コンテキストをカスタマイズして、 CustomReflectionContextクラスを介してデフォルトのリフレクション動作をオーバーライドする機能。
の目的は何ReflectionContext
ですか? MSDN は、この件に関して明確ではありません。
.NET Framework 4.5 Developer Preview の新機能に関する言及
リフレクション コンテキストをカスタマイズして、 CustomReflectionContextクラスを介してデフォルトのリフレクション動作をオーバーライドする機能。
の目的は何ReflectionContext
ですか? MSDN は、この件に関して明確ではありません。
これまでの .NET では、リフレクションによって特定の機能を自動化できるようにすることと、それらをカスタマイズできるようにすることの間で緊張が生じていました。たとえば、Visual Studio の [プロパティ] パネルを例にとると、.NET 型 (デザイン サーフェイス上のコントロールなど) が表示されるシナリオでは、型が定義するすべてのパブリック プロパティを自動的に検出して表示できます。
この種の型主導の動作にリフレクションを使用すると、コントロールの開発者が何もしなくてもすべてのプロパティが表示されるため、便利です。しかし、これには問題があります。たとえば、特定のプロパティの分類やカスタム編集 UI を定義するなど、カスタマイズしたい場合はどうすればよいでしょうか。
.NET での従来のソリューションは、一連のカスタム属性を関連するメンバーに平手打ちすることです。ただし、これに伴う 1 つの問題は、実行時に意味のある仕事をするコードの部分が、設計時にしか何もしないクラスに依存してしまうことを意味する可能性があることです。属性に依存すると、実行時と設計時の側面を分離できなくなります。 . VS のプロパティ パネル用のカスタム デザイナー UI のコードを、最終的にエンド ユーザーのコンピューターに配置されるコントロール ライブラリの一部として本当に出荷したいですか?
もう 1 つの問題は、状況によっては、提示する「プロパティ」を動的に決定したい場合があることです。この最も古い例 (.NET 1.0 にさかのぼる) の 1 つは、DataSet
ある種のグリッド コントロール (クライアント側または Web) に を配置することでした。厳密に型指定されたデータセットでは、リフレクションはソースが提供するプロパティをグリッドが検出するための適切な方法である可能性がありますが、DataSet
動的に使用することもできるため、データ グリッドが実行時に表示する列を確認する方法が必要です。
(これに対する答えの 1 つは、UI を適切に設計することです! このようにグリッドを直接生成すると、ひどいユーザー エクスペリエンスにつながります。しかし、多くの人は、それが良いアイデアであるかどうかにかかわらず、怠惰な方法でそれを行いたいと考えています...)
したがって、リフレクション駆動の動作が必要な場合もあれば、実行時に完全に制御できるようにしたい場合もあります。
このために、さまざまなアドホックなソリューションが登場しました。リフレクションの上に一種の仮想化可能なビューを提供する型の全体TypeDescriptor
とファミリがあります。PropertyDescriptor
デフォルトでは、これはリフレクションからすべてを直接渡すだけですが、型には実行時にカスタム記述子を提供することを選択する機会があり、外観を変更したり完全に置き換えたりすることができます。ICustomTypeDescriptor
その世界の一部です。
これは、必要に応じてランタイム駆動の動作を提供するオプションを使用して、デフォルトでリフレクション駆動の動作が必要であるという問題に対する 1 つの解決策を提供します。しかし、これは設計時にのみ行いたいという問題を解決するものではなく、実行時の再配布可能ファイルの一部としてそのコードを出荷する必要はありません。
そのため、数年前、Visual Studio は、設計時に型情報を拡張するための独自のアドホック メカニズムを導入しました。Visual Studio が特定のランタイム コンポーネントに関連するデザイン時コンポーネントを自動的に検出する規則主導の動作が多数あります。これにより、関連するコードを再頒布可能ファイルに焼き込む必要なく、デザイン エクスペリエンスをカスタマイズできます。Blend もこのメカニズムを使用しますが、いくつかの調整が加えられているため、VS と Blend に異なるデザイナー ピースを提供できます。
もちろん、それは通常のリフレクション API からは見えません。VS と Blend には、これをすべて機能させるためにリフレクションの上に置かれるラッパー レイヤーがあります。
これで、リフレクションにパススルーできる、またはリフレクションから得られるものを拡張できる 2 つの仮想化レイヤーができました...
.NET 4.5 のように見えますが、CLR チームは、さまざまなグループが既にこの種のことを行っており、他のグループがさらに多くのことをしたいと判断した (MEF チームは、リフレクション ドリブン ウィズ オプション ランタイムに対して同様の要件を持っていました)。 -augmentation 動作)、これはまさにランタイムに組み込まれるべきものでした。
新しいモデルは次のようです。ReflectionContext
基本クラスは、仮想化されたバージョンのリフレクション API を取得できる抽象 API です。主なアイデアの 1 つは、リフレクションの上に仮想化可能なラッパーを取得することが唯一の目標である場合、タイプ記述子システムのような特殊な API はもう必要ないということです。リフレクションはすぐに仮想化できるようになりました。こんなこと書いてもいいから
public static void ShowAllAttributes(Type t)
{
foreach (Attribute attr in t.GetCustomAttributes(true))
{
Console.WriteLine(attr);
}
}
今ではいつでもそれを書くことができましたが、.NET 4.5 より前では、このようなコードはリフレクションを使用しているため、常に「実際の」型情報に対して機能していました。しかし、リフレクション コンテキストのおかげで、これを仮想化された .xml で提供できるようになりましたType
。したがって、この非常に退屈なタイプを考えてみましょう:
class NoRealAttributes
{
}
typeof(NoRealAttributes)
私のメソッドに渡すだけShowAllAttributes
では、何も出力されません。しかし、(やや不自然な) カスタム リフレクション コンテキストを書くことができます。
class MyReflectionContext : CustomReflectionContext
{
protected override IEnumerable<object> GetCustomAttributes(MemberInfo member, IEnumerable<object> declaredAttributes)
{
if (member == typeof(NoRealAttributes))
{
return new[] { new DefaultMemberAttribute("Foo") };
}
else
{
return base.GetCustomAttributes(member, declaredAttributes);
}
}
}
(ちなみに、CustomReflectionContext
とそのベースの違いReflectionContext
は、後者が仮想化可能なリフレクション コンテキストの API を定義し、そのCustomReflectionContext
ようなものを実装しやすくするためにいくつかのヘルパーを追加していることだと思います。) そして今、私はそれを使用できます。Type
クラスに の仮想化バージョンを提供するには:
var ctx = new MyReflectionContext();
Type mapped = ctx.MapType(typeof(NoRealAttributes).GetTypeInfo());
ShowAllAttributes(mapped);
このコードでは、 はmapped
引き続きType
オブジェクトを参照しているため、リフレクション API の使用方法を知っている人はそれを操作できますが、実際には存在しない属性の存在が報告されるようになります。もちろん、Type
は抽象的であるため、そこから派生したものは常にあります。呼び出すと、通常表示されるではなく、mapped.GetType()
実際には であることがわかります。そして、そのオブジェクトは私のカスタム コンテキストに属しているので、それを介して取得した他のリフレクション API オブジェクト (たとえば、 を記述した場合) は、私のカスタム コンテキストを通過するカスタマイズされたオブジェクトも取得し、何かを変更する機会があります。他に出てくるもの。System.Reflection.Context.Custom.CustomType
System.RuntimeType
CustomType
mapped.Assembly.GetTypes()
そのため、コードは、カスタマイズされたType
オブジェクトを使用して型システムをナビゲートできます。このようなコードは通常の基本的なリフレクション API を使用していますが、必要に応じて、そこから得られるものをカスタマイズする機会があります。
この仮想化されたビューは、要求した場合にのみ取得できます。たとえば、.NET 4.5 の MEF は、ユーザー指定のカスタム リフレクション コンテキストを使用する必要があることを指定するカスタム属性を探しますが、それ以外の場合は通常のリフレクションにフォールバックします。(そして、私のShowAllAttributes
メソッドの場合、Type
渡すために選択したオブジェクトを使用します。仮想化されたオブジェクトを取得しているか、「実際の」タイプのオブジェクトを取得しているかはわかりません。)
つまり、仮想化された型情報が必要な場合に、リフレクション API のアドホック ラッパーが不要になるということです。