0

私はMEFで働いています。そして、PRISM の MVVM RI というデモを見ていましたが、プログラムの一部に次のコードが含まれています。

    /// <summary>
    /// Factory class to create a question view model for a given question object.
    /// </summary>
    private static class QuestionViewModelFactory
    {
        private static Dictionary<Type, Func<Question, QuestionViewModel>> maps = new Dictionary<Type, Func<Question, QuestionViewModel>>()
        {
            { typeof(OpenQuestion), (q) => new OpenQuestionViewModel((OpenQuestion)q) },
            { typeof(MultipleSelectionQuestion), (q) => new MultipleSelectionQuestionViewModel((MultipleSelectionQuestion)q) },
            { typeof(NumericQuestion), (q) => new NumericQuestionViewModel((NumericQuestion)q) }
        };

        public static QuestionViewModel GetViewModelForQuestion(Question question)
        {
            Func<Question, QuestionViewModel> viewModelInstanceFactory = null;
            if (maps.TryGetValue(question.GetType(), out viewModelInstanceFactory))
            {
                return viewModelInstanceFactory(question);
            }
            else
            {
                throw new ArgumentOutOfRangeException("Could not locate a view model for question type");
            }
        }
    }

    // Note that each class derived QuestionViewModel needs a constructor parameter to be created.
public abstract class QuestionViewModel : NotificationObject 
{ 
    protected QuestionViewModel() { ... } 
} 

public abstract class QuestionViewModel<T> : QuestionViewModel 
    where T : Question 
{ 
    protected QuestionViewModel(T question) { ... } 
} 

私のソフトウェアでは、この機能が必要ですが、今は発見によって行いたいと思っています。

当初、私はカスタム エクスポートを作成して保存のみし、質問タイプ モデルQuestionViewModelとして保存することを考えていました。contractNameこれをチェックして。

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ExportViewModelForProblemAttribute : ExportAttribute
{
    public ExportViewModelForProblemAttribute(Type viewModelType, Type questionType)
        : base(questionType.ToString(), typeof(QuestionViewModel))
    {
    }
}

しかし、それから私は、どうすればコンストラクターによってオブジェクトを渡すことができるでしょうか? アイデアは、qインポートを使用せずにオブジェクトを渡すことです。しかし、私はこの部分で迷子になりました。

public class ProblemViewModelFactory
{
    private readonly CompositionContainer container;

    [ImportingConstructor]
    public ProblemViewModelFactory(CompositionContainer container)
    {
        this.container = container;
    }

    public QuestionViewModelFactory GetQuestionViewModelFactory(Question question)
    {
        // what can I do to return the correspond view model with the question inside?
    }
}

このマッピングを実装して引数を渡すにはどうすればよいですか? 前もって感謝します。

4

1 に答える 1

0

MEF の Silverlight バリアントでは、ExportFactory<T, TMetadata>. このタイプが行うことは、呼び出すたびにタイプの新しいインスタンスをスピンアップするCreateExport()ことですが、パーツに関する追加情報 (メタデータ) も含まれています。

現在、あなたが行っているのは、質問名をコントラクト名として使用して質問ビュー モデルをエクスポートすることです。これでは、すべての型のインスタンスを簡単に取得することはできませんQuestionViewModel。それよりも、引き続き as としてエクスポートしQuestionViewModel、いくつかのメタデータを型に追加する必要があります。この場合、name プロパティが必要なので、メタデータを定義できます。次のように契約します。

public interface INameMetadata
{
  string Name { get; }
}

次に、エクスポート属性を変更しましょう。

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
[MetadataAttribute]
public class ExportQuestionAttribute : ExportAttribute, INameMetadata
{
  public ExportQuestionAttribute(string name)
    : base(typeof(QuestionViewModel))
  {
    this.Name = name;
  }

  public string Name { get; private set; }
}

export 属性の型を変更して、引数のみで基本コンストラクターを呼び出し、代わりにの値をpropertytypeに格納します。実際には、エクスポート属性をメタデータ コントラクトで装飾する必要はありませんが、エクスポートするときに、必要なすべてのメタデータを提供していることをコンパイル時にチェックすることが保証されるので、私はそうした方が好きです。nameNameINameMetadata

次に、コンシューマ タイプを変更できます。

[Export]
public class ProblemViewModelFactory
{
  private readonly IEnumerable<ExportFactory<Question, INameMetadata>> _questionFactories;

  [ImportingConstructor]
  public ProblemViewModelFactory(
    [ImportMany] IEnumerable<ExportFactory<Question, INameMetadata>> questionFactories)
  {
    if (questionFactories == null)
      throw new ArgumentNullException("questionFactories");

    _questionFactories = questionFactories;
  }

  public QuestionViewModel GetQuestionViewModel(string name)
  {
    return _questionFactories
      // Get matching question factories
      .Where(q => q.Metadata.Name == name)
      // Select the exported value
      .Select(q => q.CreateExport().Value)
      // First or default - what if the question doesn't exist?
      .FirstOrDefault();
  }
}

さて、この部分をいくつかの方法で変更しました。

まず、IEnumerable<ExportFactory<QuestionViewModel, INameMetata>>パーツ ファクトリのコレクションである のインスタンスのみを受け入れます。これには、エクスポートされたすべての種類の質問のファクトリが含まれている必要があります。インポート部分はメソッドです(ではなくGetQuestionViewModelを返したいと思います)。type は新しいインスタンスをスピンアップする作業を行います。これはtypeであるため、パーツを作成する前にクエリできるtypeのプロパティがあります。QuestionViewModelQuestionViewModelFactoryExportFactoryExportFactory<QuestionViewModel, INameMetadata>MetadataINameMetadata

最後のメソッドは、使用可能なファクトリのセットをクエリし、Name各インスタンスのプロパティをチェックしてINameMetadata、一致する質問を返すか、null見つからない場合に返します。また、同じ名前の複数の質問を無視し、最初のものだけを選択します (この設計上の決定はあなた次第です)。

それがあなたを正しい方向に向けてくれることを願っています。

于 2012-08-11T08:17:30.337 に答える