2012-08-11 145 views
0

我正在與MEF合作。我看着從PRISM稱爲MVVM RI演示,以及程序的一部分,有這樣的代碼:如何在不使用MEF導入的情況下將參數傳遞給構造函數?

/// <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? 
    } 
} 

我能做些什麼來實現這個映射並傳遞參數? 在此先感謝。

回答

0

使用MEF的Silverlight變體,我們可以包含一個名爲ExportFactory<T, TMetadata>的類型。這種類型所做的是在每次調用CreateExport()時創建一個新的類型實例,但它還包含有關該部分的其他信息(元數據)。

現在,您正在做的是使用問題名稱作爲合同名稱導出問題視圖模型。這並不容易獲得所有QuestionViewModel類型的實例,因此,您應該繼續導出爲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; } 
} 

我已經改變了出口屬性類型調用只用type論證的基礎構造,以及相反,將name的值存儲在屬性Name。您實際上並不需要用我們的元數據合同INameMetadata來修飾您的導出屬性,但我更喜歡它,因爲它確保在導出時,我可以在編譯時檢查我是否提供了所有必需的元數據。

接下來,我們可以進行修改,以我們的消費類型:

[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方法(我假設你想返回QuestionViewModel,而不是QuestionViewModelFactory)。 ExportFactory類型完成旋轉新實例的工作,並且由於它屬於ExportFactory<QuestionViewModel, INameMetadata>類型,因此它的Metadata屬性的類型爲INameMetadata,我們可以在創建零件之前查詢該屬性。

的最後一個方法將查詢組可用的工廠,檢查每個INameMetadata實例的Name財產,並返回相匹配,或者null如果不能發現問題。它也會忽略同名的多個問題,並且只選擇第一個(這個設計決定將由您決定)。

我希望你指出正確的方向。

+0

感謝您的答案,但我想我不理解,QuestionViewModel將如何具有Question對象參數?這對我來說ExportFactory和Metadata標籤有點混亂。 – 2012-08-11 20:11:22

相關問題