我一直关注StockTrader RI for PRISM的内部运作。
在此RI中,MEF和自定义属性系统组合使用以在区域中注册视图,而不是将事物连接到模块初始化程序中的RegionManager。
更具体地说,有ViewExportAttribute
实现:
MetaDataAttribute
IViewRegionRegistration
MetaDataAttribute和"属性视图" IViewRegionRegistration
中的System.Lazy<T,TMetaData>
可以AutoPopulateExportedViewsBehavior
利用System.Lazy<T,TMetaData>
来实现区域和观点的正确链接。
一般而言,public interface IMessageSenderCapabilities
{
MessageTransport Transport { get; }
bool IsSecure { get; }
}
与实际元数据之间的相互作用详细阐述here,更具体地说是“#34;使用强类型元数据&#34;”部分。
要清楚,我理解Lazy的意图,它显然有效。但是,我完全不理解的是在属性提供的元数据视图(仅仅是一个接口)和使用MetaDataAttribute提供的实际数据填充TMetaData属性之间链接的位置和方式
通过previously referenced example:
让我的请求更加清晰首先,定义了一个接口,可以作为一种模板来传递某些元数据:
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class MessageSenderAttribute : ExportAttribute
{
public MessageSenderAttribute() : base(typeof(IMessageSender)) { }
public MessageTransport Transport { get; set; }
public bool IsSecure { get; set; }
}
接下来,定义了相应的MetaDataAttribute(它具有与前一个界面相同的属性)
[MessageSender(Transport=MessageTransport.Smtp, IsSecure=true)]
public class SecureEmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}
该属性可用于导出,其中为属性属性设置实际值:
public class HttpServerHealthMonitor
{
[ImportMany]
public Lazy<IMessageSender, IMessageSenderCapabilities>[] Senders { get; set; }
public void SendNotification()
{
foreach(var sender in Senders)
{
if (sender.Metadata.Transport == MessageTransport.Smtp &&
sender.Metadata.IsSecure)
{
var messageSender = sender.Value;
messageSender.Send("Server is fine");
break;
}
}
}
}
最后,我们可以进行一些导入:
sender.Metadata.Transport
在最后一步中:{{1}}在非常懒惰的&lt;&gt;上进行评估。因此,在某个地方,Lazy了解元数据的实际值,而不仅仅是它传递的接口。 我想了解这是怎么发生的,是谁或者是谁负责。即使这只是一个非常普遍的流程。
答案 0 :(得分:1)
经过一些反思我觉得我可以开始制定一个答案,虽然事实证明很多事情正在发生,所以这个答案可能会发展。我正在写下来听听我自己学习的好处。
MEFBootsrapper.Run()
...
MEFBootstrapper.Container.GetExports(...)
因为CompositionContainer : ExportProvider, ...
和ExportProvider定义了public Lazy<T, TMetadataView> GetExport<T, TMetadataView>()
。
下一个private Lazy<T, TMetadataView> GetExportCore<T, TMetadataView>(string contractName)
下一个internal static Lazy<T, M> CreateStronglyTypedLazyOfTM<T, M>(Export export)
在这里,AttributedModelServices.GetMetadataView<M>(export.Metadata)
其中M是MetaDataView的类型。鉴于导出本身属于System.ComponentModel.Composition.Primitives.Export
类型,而且其字段ExportDefenition
存在继承的AttributedExportDefenition
。
AttributedExportDefenition.MetaData
其获取者包含this._member.TryExportMetadataForMember(out strs);
TryExportMetadataForMember(...)
最后有一个支票type.IsAttributeDefined<MetadataAttributeAttribute>
,以查看是否已在问题中应用了MessageSenderAttribute
的MetadataAttribute。
所以这或多或少(非常粗略地)我们如何获得导出的实际元数据,因此可能会有更多的弯路,这些导出的元数据也会到达懒惰,尽管我仍然要知道它是如何工作的。
任何反馈仍然会受到赞赏。
答案 1 :(得分:0)
试图理解原始问题中的代码发生了什么,产生了另一个问题:
StockTrader RI与MEF Documentation
中提供的示例之间存在细微差别在Stocktrader中,定义了ViewExportAttribute
:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
[MetadataAttribute]
public sealed class ViewExportAttribute : ExportAttribute, IViewRegionRegistration
{
... omitted for brevity ...
}
MEF文档给出了一个类似的例子(也在最初的问题中):
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class MessageSenderAttribute : ExportAttribute
{
public MessageSenderAttribute() : base(typeof(IMessageSender)) { }
public MessageTransport Transport { get; set; }
public bool IsSecure { get; set; }
}
所以使用上面的代码块,不同之处在于,在第一种情况下,属性派生自定义&#34;元数据视图的接口&#34;而在第二个例子中,情况并非如此;该属性与IMessageSenderCapabilities
接口具有相同的属性。
&#34;没什么大不了的,#34;你会想,但后来在StockTrader RI:
[ImportMany(AllowRecomposition = true)]
public Lazy<object, IViewRegionRegistration>[] RegisteredViews { get; set; }
而在MEF示例中:
[ImportMany]
public Lazy<IMessageSender, IMessageSenderCapabilities>[] Senders { get; set; }
所以这里的不同之处在于,在Stocktrader RI中,我们尝试懒惰导入的类型未指定(它只是对象),而在第二种情况下,它更具体地定义(IMessageSender)。
最终结果或多或少相同,某些类型是随着元数据一起进行Lazily导入。
但是,我还想了解的是:
ViewExportAttribute
具体来自IViewRegionRegistration
我们以后可以Lazy<object, ...
,即系统知道要导入什么,因为只导入带有该元数据的类型?所有这些都没有指定object
实际上是视图,即UserControls?