[英]How to pass a parameter into the constructor without import using MEF?
我正在與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
而不使用Import。 但是我迷路了。
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?
}
}
如何實現此映射並傳遞參數? 提前致謝。
使用MEF的Silverlight變體,我們可以包含一個名為ExportFactory<T, TMetadata>
。 這種類型的作用是每次我們在其上調用CreateExport()
時都會旋轉該類型的新實例,但是它還包含有關該零件的一些其他信息(元數據)。
現在,您當前正在執行的操作是使用問題名稱作為合同名稱來導出問題視圖模型。 這將不容易獲得所有QuestionViewModel
類型的實例,因此,相反,您應繼續導出為QuestionViewModel
並將一些元數據附加到該類型,因此在這種情況下,您需要一個name屬性,以便我們可以定義我們的元數據合同為:
public interface INameMetadata
{
string Name { get; }
}
現在,讓我們對export屬性進行修改:
[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>
,因此它具有一個INameMetadata
類型的Metadata
屬性,我們可以在創建零件之前對其進行查詢。
最后一個方法將查詢可用工廠集,檢查每個INameMetadata
實例的Name
屬性,並返回匹配的問題;如果找不到一個,則返回null
。 它還將忽略具有相同名稱的多個問題,並僅選擇第一個(此設計決定取決於您)。
我希望這會為您指明正確的方向。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.