Movatterモバイル変換


[0]ホーム

URL:


スマートフォン専用ページを表示

ぬるり。

ぬるりことNullReferenceExceptionに怯えながら日々書き連ねる.NETのコード片(主にC#)
記事検索
 
<<2010年12月>>
   1234
5678 91011
12131415161718
19202122232425
262728293031 
新着記事
(12/09)"ASSOCIATORS OF" on System.Management
(10/03)ScrollIntoView(TextElement)
(09/01)MenuItemとHierarchicalDataTemplate /WPF
(08/31)MenuItemとCompositeCollectionをバインド /WPF
(08/27)MenuItemをバインド /WPF
カテゴリ
日記(5)
C#(26)
VB.NET(7)
.NET(38)
C++/CLI(1)
WPF(5)
過去ログ
2010年12月(1)
2010年10月(1)
2010年09月(1)
2010年08月(2)
2010年05月(1)
2010年03月(1)
2010年01月(1)
2009年12月(1)
2008年07月(1)
2008年04月(2)
2008年03月(3)
2008年02月(1)
2007年10月(1)
2007年08月(1)
2007年03月(3)
2006年12月(1)
2006年10月(1)
2006年06月(1)
2006年05月(1)
2006年04月(6)
最近のコメント
グローバルフック・ザ・キーボード by at (10/18)
グローバルフック・ザ・キーボード by at (10/18)
グローバルフック・ザ・キーボード by 田中 (04/10)
グローバルフック・ザ・キーボード by 田中 (04/10)
他プロセスのメモリへのちょっかい@タブコントロール by (05/28)
最近のトラックバック
C# と NTFS ストリームの甘くなくもない関係 byhttp://www.valras-plage.net/max-test-ultra/(12/03)
動的なDLLインポート by正しい選択(08/10)
COM クライアント実装の道程 for TaskScheduler その番外編2 〜 COM オブジェクトと GC とファイナライザ by黒龍's Blog(06/30)
From Structure To Bytes byPukiWiki/TrackBack 0.1(11/10)
マルチメディアタイマ byAppli Wiki (PukiWiki/TrackBack 0.3)(04/25)
RDF Site Summary
RSS 2.0
<<二次元配列をもっとビュー 5 |TOP |メソッドの型引数を使った引数>>

2008年07月05日

ジェネリックカレー

あんまり管理もしてない今日この頃ですが皆様いか(略)。

今回は型引数をバインドするカリー化ができないかと言う話。

一応解説しておくと、カリー化とは要するに引数の一部を固定した関数を作ることです。こんなサンプルコードでご理解いただけるでしょうか。

staticint Add(int x,int y) {return x + y; }staticint Add5(int x) {return Add(x, 5); }publicstaticvoid Main() {    Console.WriteLine(Add5(4));}

この場合、Add メソッドの引数 y を 5 に固定した Add5 メソッドを新たに作成しています。まあサンプルのためのサンプルなんで意味は無いですけどね。ちなみに関数作成はラムダ式など使って表現することが多いです。

staticvoid Main() {    Func<int,int> addx = x => Add(x, 5);    Console.WriteLine(addx(4));}' ちなみに VB だとラムダ式はこんな形になるそうな。PublicSharedSub Main()Dim addxAs Func(OfInteger,Integer) =Function(x) Add(x, 5)    Console.WriteLine(addx(4))End Sub

さて本題ですが、まず何をやりたかったのかから説明しましょう。

幾つかのアセンブリから、特定の型の派生クラスの一覧を調べようと思ったのがきっかけでした。具体的に言うと WPF の MarkupExtension の派生クラスを。

取りあえずベタに書きます。

publicstaticvoid Main() {var types1 =typeof(Window).Assembly.GetTypes()                   .Where(type => type.IsSubclassOf(typeof(MarkupExtension)));var types2 =typeof(Rect).Assembly.GetTypes()                   .Where(type => type.IsSubclassOf(typeof(MarkupExtension)));var types3 =typeof(Duration).Assembly.GetTypes()                   .Where(type => type.IsSubclassOf(typeof(MarkupExtension)));// 以下、types を Concat したり表示したり}

露骨に記述が重複しているので、これはメソッドにするのが一般的でしょう。

publicstatic IEnumerable<Type> GetMarkupExtensions(Type type) {return type.Assembly.GetTypes()                   .Where(t => t.IsSubclassOf(typeof(MarkupExtension)));}publicstaticvoid Main() {var types1 = GetMarkupExtensions(typeof(Window));}

引数が Type 型なら、一々呼び出し元で typeof するより、型引数で表現して GetMarkupExtensions メソッド内でtypeof した方がすっきりする気がします。

publicstatic IEnumerable<Type> GetMarkupExtensions<T>() {return GetMarkupExtensions(typeof(T));}publicstaticvoid Main() {var types1 = GetMarkupExtensions<Window>();}

ここでこの GetMarkupExtensions を汎用化することを考えます。つまり、任意のアセンブリ(に属する型)から任意の型の派生クラスを列挙するメソッドです。

publicstatic IEnumerable<Type> GetSubclasses<TAnyInAssembly, TBase>() {returntypeof(TAnyInAssembly).Assembly.GetTypes()                   .Where(t => t.IsSubclassOf(typeof(TBase)));}publicstaticvoid Main() {var types1 = GetSubclasses<Window, MarkupExtension>();var types2 = GetSubclasses<Rect, MarkupExtension>();var types3 = GetSubclasses<Duration, MarkupExtension>();}

汎用化した結果、逆に Main の方で記述が増えてしまいました。どうせ型引数のうち MarkupExtension は同じなんですからこれを固定して型引数一つで済ませたい。こんな感じです。

publicstaticvoid Main() {var func = BindToGetSubclasses<MarkupExtension>();var types1 = func<Window>();var types2 = func<Rect>();var types3 = func<Duration>();}

BindToGetSubclasses は Func<IEnumerable<Type>> 相当のデリゲートインスタンスを返すことになりますが、ここで困ったことになります。デリゲートインスタンスは作成時点で既に型引数は解決済みでなければならないのです。インスタンスですから当然ですが。

てなわけでメソッドでは解決できないようです。ここはもう一つ大きい区切り、つまりクラスに目をやります。クラスにも型引数を使用できます。ならばこちらでバインドしてやればいいのではないか。

publicclass SubclassEnumerator<TBase> {public IEnumerable<Type> GetSubclasses<TAnyInAssembly>() {returntypeof(TAnyInAssembly).Assembly.GetTypes()                   .Where(t => t.IsSubclassOf(typeof(TBase)));    }}publicstaticvoid Main() {var e =new SubclassEnumerator<MarkupExtension>();var types1 = e.GetSubclasses<Window>();var types2 = e.GetSubclasses<Rect>();var types3 = e.GetSubclasses<Duration>();}

これでほぼ BindToGetSubclasses と同じ記述になりました。

しかし一々クラスを用意しなければならないってのはちょっと面倒ですね。

posted by Hongliang at 13:01|Comment(0)|TrackBack(0)|C#|このブログの読者になる|更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック

ここ(hongliang.seesaa.net)で公開しているものについて、利用は自由に行って頂いて構いません。改変、再頒布もお好きになさって下さい。利用に対しこちらが何かを要求することはありません。

ただし、公開するものを使用、または参考したことによって何らかの損害等が生じた場合でも、私はいかなる責任も負いません。

あ、こんなのに使ったってコメントを頂ければ嬉しいです。

Powered by Seesaa
×

この広告は90日以上新しい記事の投稿がないブログに表示されております。


[8]ページ先頭

©2009-2025 Movatter.jp