了解MEF System.Lazy <t,tmetadata> </t,tmetadata>

时间:2014-07-29 16:28:45

标签: c# mvvm prism mef

我一直关注StockTrader RI for PRISM的内部运作。

在此RI中,MEF和自定义属性系统组合使用以在区域中注册视图,而不是将事物连接到模块初始化程序中的RegionManager。

更具体地说,有ViewExportAttribute实现:

  1. MetaDataAttribute
  2. IViewRegionRegistration
  3. MetaDataAttribute和&#34;属性视图&#34; 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了解元数据的实际值,而不仅仅是它传递的接口。 我想了解这是怎么发生的,是谁或者是谁负责。即使这只是一个非常普遍的流程。

2 个答案:

答案 0 :(得分:1)

经过一些反思我觉得我可以开始制定一个答案,虽然事实证明很多事情正在发生,所以这个答案可能会发展。我正在写下来听听我自己学习的好处。

  1. MEFBootsrapper.Run()

    ...

  2. MEFBootstrapper.Container.GetExports(...)因为CompositionContainer : ExportProvider, ...和ExportProvider定义了public Lazy<T, TMetadataView> GetExport<T, TMetadataView>()

  3. 下一个private Lazy<T, TMetadataView> GetExportCore<T, TMetadataView>(string contractName)

  4. 下一个internal static Lazy<T, M> CreateStronglyTypedLazyOfTM<T, M>(Export export)

  5. 在这里,AttributedModelServices.GetMetadataView<M>(export.Metadata)其中M是MetaDataView的类型。鉴于导出本身属于System.ComponentModel.Composition.Primitives.Export类型,而且其字段ExportDefenition存在继承的AttributedExportDefenition

  6. AttributedExportDefenition.MetaData其获取者包含this._member.TryExportMetadataForMember(out strs);

  7. TryExportMetadataForMember(...)最后有一个支票type.IsAttributeDefined<MetadataAttributeAttribute>,以查看是否已在问题中应用了MessageSenderAttribute的MetadataAttribute。

  8. 所以这或多或少(非常粗略地)我们如何获得导出的实际元数据,因此可能会有更多的弯路,这些导出的元数据也会到达懒惰,尽管我仍然要知道它是如何工作的。

    任何反馈仍然会受到赞赏。

答案 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导入。

但是,我还想了解的是:

  1. 如果两个示例中各个关键点的差异相关。
  2. 特别是在股票交易者示例中,我们如何知道要导入什么作为懒惰?是因为ViewExportAttribute具体来自IViewRegionRegistration我们以后可以Lazy<object, ...,即系统知道要导入什么,因为只导入带有该元数据的类型?所有这些都没有指定object实际上是视图,即UserControls?