【MEF】自作カタログ 絶対真似しないでください危険です。

  • 2010.05.25 Tuesday
  • 20:59
JUGEMテーマ:コンピュータ

Source and Project


※当Blogの最近のMEFの投稿はMEFフレームワークを必ずしも正しい使い方をしているとは限りませんので注意してください。

ComposablePartCatalog クラス、ComposablePartDefinition クラス、ComposablePart クラスを使用して自作カタログを作成しました。クラスのそれぞれの責務はMSDNライブラリーによると

-------------------
ComposablePartCatalog クラス
ComposablePartDefinition オブジェクトを収集して返すコンポーザブル パーツ カタログの抽象基本クラスを表します。

ComposablePartDefinition クラス
ComposablePart オブジェクトの作成を記述して有効にするコンポーザブル パーツ定義の抽象基本クラスを定義します。

ComposablePart クラス
オブジェクトをインポートしたり、エクスポートされたオブジェクトを生成したりするコンポーザブル パーツの抽象基本クラスを定義します。
--------------------

カタログを自作したり拡張したい場合にすべてをこれらの抽象クラスから直接継承する必要は全くないと思いますが、これらの抽象クラスのメンバーがいつ呼ばれるのかシーケンスが知りたいのと、属性付きプログラミング モデル以外でも実装可能なことを試してみたいなど、いろいろやってみたいことがあったので、実装してみました。

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Primitives;
using System.Linq;

namespace Art55.MEF.JunkLib
{
    public class MyComposablePartCatalog : ComposablePartCatalog
    {
        public MyComposablePartCatalog(params Type[] types)
        {
            _partDefinitionList = new List<ComposablePartDefinition>();
            foreach (Type type in types)
            {
                _partDefinitionList.Add(new MyComposablePartDefinition(type));
            }
        }

        public override IQueryable<ComposablePartDefinition> Parts
        {
            get { return _partDefinitionList.AsQueryable(); }
        }

        private readonly List<ComposablePartDefinition> _partDefinitionList;
    }
}


using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using System.Reflection;

namespace Art55.MEF.JunkLib
{
    class MyComposablePartDefinition : ComposablePartDefinition
    {
        public MyComposablePartDefinition(Type type)
        {
            _type = type;
            var metadata = new Dictionary<string, object>();
            metadata[CompositionConstants.ExportTypeIdentityMetadataName] =
                AttributedModelServices.GetTypeIdentity(type);
            _rootExportDefinition = new ExportDefinition(AttributedModelServices.GetContractName(type), metadata);
            _exportDefinitionList = new List<ExportDefinition> { _rootExportDefinition };
            _importDefinitionList = new Dictionary<ImportDefinition, PropertyInfo>();
            foreach (PropertyInfo propertyInfo in type.GetProperties())
            {
                if (propertyInfo.CanWrite)
                {
                    Type importType = propertyInfo.PropertyType;
                    var importDefinition = new ContractBasedImportDefinition(
                        AttributedModelServices.GetContractName(importType),
                        AttributedModelServices.GetTypeIdentity(importType),
                        Enumerable.Empty<KeyValuePair<string, Type>>(),
                        ImportCardinality.ExactlyOne,
                        false,
                        false,
                        CreationPolicy.Shared);
                    _importDefinitionList.Add(importDefinition, propertyInfo);
                }
            }
        }

        public override IEnumerable<ExportDefinition> ExportDefinitions
        {
            get { return _exportDefinitionList; }
        }

        public override IEnumerable<ImportDefinition> ImportDefinitions
        {
            get { return _importDefinitionList.Keys; }
        }

        public override ComposablePart CreatePart()
        {
            return new MyComposablePart(this);
        }

        public Export CreateExport()
        {
            return new Export(_rootExportDefinition, () => Activator.CreateInstance(_type));
        }

        internal void SetImport(object obj, ImportDefinition importDefinition, Export export)
        {
            if (_importDefinitionList.ContainsKey(importDefinition))
            {
                PropertyInfo propertyInfo = _importDefinitionList[importDefinition];
                propertyInfo.SetValue(obj, export.Value, null);
            }
        }

        private readonly Type _type;
        private readonly ExportDefinition _rootExportDefinition;
        private readonly List<ExportDefinition> _exportDefinitionList;
        private readonly Dictionary<ImportDefinition, PropertyInfo> _importDefinitionList;
    }
}


using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Primitives;
using System.Linq;

namespace Art55.MEF.JunkLib
{
    class MyComposablePart : ComposablePart
    {
        public MyComposablePart(MyComposablePartDefinition definition)
        {
            if (definition == null)
                throw new ArgumentNullException("definition");

            _definition = definition;
        }

        public override IEnumerable<ExportDefinition> ExportDefinitions
        {
            get { return _definition.ExportDefinitions; }
        }

        public override IEnumerable<ImportDefinition> ImportDefinitions
        {
            get { return _definition.ImportDefinitions; }
        }

        public override object GetExportedValue(ExportDefinition definition)
        {
            if (_definition.Equals(definition))
                throw new ArgumentException("definition");

            object result = _definition.CreateExport().Value;
            foreach (ImportDefinition importDefinition in _importSetting.Keys)
            {
                if (_importSetting.ContainsKey(importDefinition) && _importSetting[importDefinition].Count() == 1)
                {
                    _definition.SetImport(result, importDefinition, _importSetting[importDefinition].First());
                }
            }
            return result;
        }

        public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)
        {
            _importSetting[definition] = exports;
        }

        private readonly Dictionary<ImportDefinition, IEnumerable<Export>> _importSetting = new Dictionary<ImportDefinition, IEnumerable<Export>>();
        private readonly MyComposablePartDefinition _definition;
    }
}

これらのクラスを使用してカタログを作成すると

指定したTypeは必ずExportとなり、publicなGetterが存在するプロパティは必ずImportとして設定されます。そして、Exportからインスタンスを作成時にインジェクションされます。実際のライブラリーを使用してインスタンスを作成するコードを書いてみると

using System;
using System.ComponentModel.Composition.Hosting;
using Art55.MEF.JunkLib;

namespace Art55.MEFSample20100525_001
{
    class Program
    {
        static void Main(string[] args)
        {
            var types = new[] {typeof (B), typeof (A), typeof (C)};
            var catalog = new MyComposablePartCatalog(types);
            var container = new CompositionContainer(catalog);
            A a = container.GetExportedValue<A>();
            a.Say();
        }
    }

    public class A
    {
        public B BObject { private get; set; }
        public void Say()
        {
            BObject.Say();
        }
    }

    public class B
    {
        public C CObject { private get; set; }
        public void Say()
        {
            CObject.Say();
        }
    }

    public class C
    {
        public void Say()
        {
            Console.WriteLine("C Say");
        }
    }
}

実行すると

C Say

と出力されます。一応、属性指定なしにExportやImportが指定可能なカタログが作成できました。

Source and Project

コメント
管理者の承認待ちコメントです。
  • -
  • 2018/04/19 2:36 AM
コメントする








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

calendar

S M T W T F S
    123
45678910
11121314151617
18192021222324
252627282930 
<< November 2018 >>

あわせて読みたい

あわせて読みたいブログパーツ

selected entries

categories

archives

recent comment

  • 【キーボード】6年前のRealForceを復活させることはできる!?その3
    art55 (05/22)
  • 【キーボード】6年前のRealForceを復活させることはできる!?その3
    分解大好き (05/18)
  • 【.NET Framework 4.5】 IListがIReadOnlyListを継承してない理由。
    art55 (02/04)
  • 【.NET Framework 4.5】 IListがIReadOnlyListを継承してない理由。
    Gen (02/04)
  • 【キーボード】RealForce が壊れて帰ってきた。
    art55 (04/29)
  • 【.NET Framework 4.5】 IListがIReadOnlyListを継承してない理由。
    art55 (02/23)
  • 【.NET Framework 4.5】 IListがIReadOnlyListを継承してない理由。
    かるあ (02/22)
  • 【C#】Dictionaryの実装・データ構造・アルゴリズムを観察する。
    art55 (01/16)
  • 【C#】Dictionaryの実装・データ構造・アルゴリズムを観察する。
    karuakun (01/16)
  • 【NetOffice】【Excel】死なないExcelプロセスをKillする。
    art55 (12/05)

recent trackback

recommend

recommend

recommend

C#プログラマのための.NETアプリケーション最適化技法 (Programmer's SELECTION)
C#プログラマのための.NETアプリケーション最適化技法 (Programmer's SELECTION) (JUGEMレビュー »)
Sasha Goldshtein,Dima Zurbalev,Ido Flatow,サシャ・ゴルドシュタイン,ディマ・ズルバレフ,イド・フラトー

recommend

ろんりと集合
ろんりと集合 (JUGEMレビュー »)
中内 伸光
とてもわかりやすいです。

recommend

recommend

シャノン・ノイマン・ディジタル世界
シャノン・ノイマン・ディジタル世界 (JUGEMレビュー »)
市川 忠男
4章がリレーショナルデータベースな内容になってます。ページ数があまりありませんが、ポイントがものすごく的確にまとまっていて、感動します。

recommend

recommend

東プレ Realforce91UBK-S 静音キーボード 静電容量無接点方式 変荷重 ブラック NG01BS
東プレ Realforce91UBK-S 静音キーボード 静電容量無接点方式 変荷重 ブラック NG01BS (JUGEMレビュー »)

テンキーレス、静音のRealForce91UBK-S。スコスコ感がたまらなく気持ちいいです。家と会社で2台持ってます。

recommend

recommend

プログラミング.NET Framework 第4版 (プログラミングシリーズ)
プログラミング.NET Framework 第4版 (プログラミングシリーズ) (JUGEMレビュー »)
Jeffrey Richter
発売予定美 2013年10月10日。.NET Frameworkとお付き合いする人のバイブルですね。

recommend

recommend

キャット・シッターの君に。
キャット・シッターの君に。 (JUGEMレビュー »)
喜多嶋 隆
私のイラストレータデビュー本です。

recommend

Essential .NET ― 共通言語ランタイムの本質
Essential .NET ― 共通言語ランタイムの本質 (JUGEMレビュー »)
ドン・ボックス,クリス・セルズ,Don Box,Chris Sells,吉松 史彰

links

profile

search this site.

others

mobile

qrcode

powered

無料ブログ作成サービス JUGEM