我正和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))
{
}
}
然后我说,我怎么能通过构造函数传递对象?我们的想法是在不使用Import的情况下传递对象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 :(得分: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
来装饰您的导出属性,但我更喜欢这样,因为它确保在导出时,我会在编译时检查我是否提供了所有必需的元数据。 / p>
接下来,我们可以对我们的消费者类型进行修改:
[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
的{{1}}属性我们可以在创建我们的部分之前进行查询。
最后一个方法将查询可用工厂集,检查每个INameMetadata
实例的Name
属性,并返回匹配的问题,或INameMetadata
如果找不到。它也会忽略具有相同名称的多个问题,并仅选择第一个问题(此设计决定将取决于您)。
我希望指出你正确的方向。