0

これは簡単かもしれませんが、私は MEF アリーナに慣れていないため、問題の解決策を見つけるのに苦労しています。

MEFをDIコンテナとしてWPF + Prismを使用するアプリケーションに取り組んでいます。RuleFileRuleFile1.ruleapp などのファイルに関連付けることで、オブジェクト (つまり) を各アプリケーション インスタンスに関連付けたいと考えています。そのため、属性で装飾し[PartCreationPolicy(CreationPolicy.Shared)]てシングルトンとして扱い、各アプリケーション インスタンスでアプリケーション全体で同じままになるようにしました。

[Serializable()]
[Export]    
[PartCreationPolicy(CreationPolicy.Shared)]
public class RuleFile : NotifyPropertyChanged, IRuleFile { }

次に、以下のように ViewModel のとき[ImportingContructor]、目的のオブジェクトは同じです。

[ImportingConstructor]
public RuleViewModel(RuleFile ruleFile)

[ImportingConstructor]
public SchemaViewModel(RuleFile ruleFile)

これまでのところ、すべてがスムーズです。

以下のコードを使用して、上記のようにビューモデルに渡される同じエクスポートされたオブジェクトを取得しようとしていますが、container.GetExportedValue<IRuleFile>()同じではない新しいオブジェクト参照を提供しています:

var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
var exportObj = container.GetExportedValue<IRuleFile>();

質問 1:オブジェクトは、シングルトン オブジェクトと同じであるはずなのに、異なる参照を取得するのはなぜCreationPolicy.Sharedですか?

質問 2:RuleFile最終的には、エクスポートされたオブジェクトを MEF DI コンテナー内の逆シリアル化されたオブジェクトと交換/置換するためにすべての作業が行われますか?

4

1 に答える 1

1

MEF コンテナー内のインスタンスを置き換えないでください。これは、そのしくみではなく、危険であり、完全に管理できません。(また、C# は、ポイント先のオブジェクトを単純に変更できる C ではないことに注意してください)。クラス X がコンテナからインスタンスを取得し、このインスタンスを別のクラス Y に渡すファクトリ メソッドを持っているとします。ここで突然、そのインスタンスを「置換」したいとします。まず、古いインスタンスをどうする必要があるでしょうか? 処分?生かした?おばあちゃんに郵送?次に、X が を使用してインスタンスを取得した場合GetExportedValue、そのインスタンスがなくなり、別のものに置き換えられたことをどのように通知しますか? できません.. 第三に、X が使用されたとします。Import代わりに、何らかの魔法によって、インスタンスが置き換えられたことが通知されます。次に、インスタンスが置き換えられたことを Y に通知するにはどうすればよいでしょうか? Yなどのリストを保持しない限り、できません。これにより、コンテナ内のオブジェクトを置き換えることは良い考えではないことが明らかになったと思います。

ただし、代わりにできることがいくつかあります。

  1. RuleFile が作成され、コンテナーに挿入されてから、どこかにインポートされることを確認してください。これも最も理にかなっています。RuleFile はある種のアプリケーション全体の構成であるという印象を持っているため、この構成はアプリケーションが起動する前に完全にセットアップすることが望ましいです。をオーバーライドMefBootstrapper.ConfigureContainerし、RuleFile インスタンスをデシリアライズComposeExportedValueして、コンテナー内の唯一のインスタンスとして設定するために使用します。逆シリアル化が失敗した場合は、エラー ダイアログを表示してアプリを中止するか、既定の構成を提供して代わりにそれを挿入します。

  2. 利用可能な場合はデシリアライズされた RuleFile から読み取るか、そうでない場合はデフォルト値を提供する RuleFile のラッパーを提供します。したがって、観測された動作は、コンテナー内で置き換えられた RuleFile と同じです。ただし、これには、ファイルがロードされる前に IRuleFile インスタンスを使用するコードがある場合、ファイルがロードされた後とは異なる値を取得するという大きな欠点があります。これが、最初のアプローチの方が優れている理由です。例:

    private class DefaultRuleFile: IRulefile
    {
      string SomeProperty
      {
        get{ return "DefaultValue"; }
      }
    }
    
    [Export( typeof( IRulefile ) )]    
    [Export( typeof( RuleFileImplementation ) )]    
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class RuleFileImplementation : IRulefile
    {
      private IRuleFile impl;
    
      RuleFileImplementation()
      {
        impl = new DefaultRuleFile();
      }
    
      string SomeProperty
      {
        get{ return impl.SomeProperty; }
      }
    
      void LoadFromFile( string file )
      {
        impl = SerializationHelper.Deserialize<IRuleFile>( file );
      }
    }
    
    //at some point in the application:
    container.GetExportedValue<RuleFileImplementation>().LoadFromFile( "file" )
    
于 2014-09-01T09:20:44.400 に答える