欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#在MEF框架中實現(xiàn)延遲加載部件

 更新時間:2022年06月23日 11:29:02   作者:天方  
這篇文章介紹了C#在MEF框架中實現(xiàn)延遲加載部件的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

在MEF的宿主中,當我們通過Import聲明導入的對象時,組裝(Compose)的時候會創(chuàng)建該對象。例如:

    interface ILogger
    {
        void Log(string message);
    }

    [Export(typeof(ILogger))]
    class ConsoleLogger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine("logger 1" + message);
        }
    }

    class Host
    {
        [Import]
        ILogger _logger = null;

        public Host()
        {
            var catalog = new AssemblyCatalog(this.GetType().Assembly);
            var container = new CompositionContainer(catalog);

            //這兒會創(chuàng)建ConsoleLogger對象
            container.ComposeParts(this);

            _logger.Log("hello world");
        }
    }

有的時候,有些組件的創(chuàng)建開銷比較大,但又不會立即使用。此時,我們希望通過延遲初始化的方式將其延遲到使用的時候創(chuàng)建,從而提高性能(常見的是提高啟動速度)。MEF是支持這一模式的,我們只需要修改一下導入的聲明形式即可。

    [Import]
    Lazy<ILogger> _logger = null;

這樣,Logger就會延遲到第一次使用的時候創(chuàng)建了。

元數(shù)據(jù)MetaData

有的時候,對于同一個服務有多個提供者,我們需要從中選擇一個使用。MEF提供了ImportMany來解決這一需求。

有的時候,對于同一個服務有多個提供者,我們需要從中選擇一個使用。MEF提供了ImportMany來解決這一需求。

    [Export(typeof(ILogger))]
    class ConsoleLogger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine(message);
        }
    }

    [Export(typeof(ILogger))]
    class DbLogger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine(message);
        }
    }

    class Host
    {
        [ImportMany]
        ILogger[] _logger = null;


        public Host()
        {
            var catalog = new AssemblyCatalog(this.GetType().Assembly);
            var container = new CompositionContainer(catalog);

            container.ComposeParts(this);

            _logger.FirstOrDefault(i => i is DbLogger).Log("hello world");
        }
    }

此時,如果我們想使用延遲導入的時候,就會變成如下形式:

    class Host
    {
        [ImportMany]
        Lazy<ILogger>[] _loggerServices = null;

        public Host()
        {
            var catalog = new AssemblyCatalog(this.GetType().Assembly);
            var container = new CompositionContainer(catalog);

            //這兒會創(chuàng)建ConsoleLogger對象
            container.ComposeParts(this);

            _loggerServices.FirstOrDefault(i => i.Value is DbLogger).Value.Log("hello world");
        }
    }

咋一看并沒有什么問題,所有的Logger都是延遲創(chuàng)建的。但是仔細分析一下就會發(fā)現(xiàn),要找到DbLogger的時候,必須遍歷所有的_loggerServices,這個遍歷會導致創(chuàng)建Logger。也就是說,使用第一個Logger的時候可能創(chuàng)建所有的Logger。

那么,如何實現(xiàn)我們只創(chuàng)建所需要的Logger呢? 這個時候就輪到元數(shù)據(jù)出場了,MEF中的元數(shù)據(jù)可以將一個數(shù)據(jù)附加到Export的服務對象中一并導出,從而可以通過元素據(jù)找到對應的服務。首先我們看看最終的效果吧:

    public interface ILoggerData
    {
        string Name { get; }
    }

    class Host
    {
        [ImportMany]
        Lazy<ILogger, ILoggerData>[] _logger = null;

        public Host()
        {
            var catalog = new AssemblyCatalog(this.GetType().Assembly);
            var container = new CompositionContainer(catalog);

            container.ComposeParts(this);

            _logger.FirstOrDefault(i => i.Metadata.Name == "DB Logger").Value.Log("hello world");
        }
    }

這里首先聲明了一個元數(shù)據(jù)類型的接口ILoggerData,然后,導入的對象變成了Lazy<ILogger, ILoggerData>,這個對象有一個屬性為Metadata,它的類型就是剛才聲明的ILoggerData。導出的ILogger對象是延遲創(chuàng)建的,而元數(shù)據(jù)不是延遲創(chuàng)建的。我們可以通過遍歷ILoggerData來找到所需要的Logger對象,從而實現(xiàn)只創(chuàng)建所使用的Logger對象。

現(xiàn)在的問題是:如何在導出的時候聲明相關的元數(shù)據(jù)。MEF提供了兩種方式:

通過ExportMetadataAttribute標記聲明

這種方式是在導出的服務的時候一并通過ExportMetaDataAttribute屬性標記元素據(jù):

    [ExportMetadata("Name", "Console Logger")]
    [Export(typeof(ILogger))]
    class ConsoleLogger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine(message);
        }
    }

    [ExportMetadata("Name", "DB Logger")]
    [Export(typeof(ILogger))]
    class DbLogger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine(message);
        }
    }

ExportMetaDataAttribute有兩個參數(shù),Name和Value,Name為屬性名稱,Value為屬性值。Compse的時候,MEF會先創(chuàng)建一個實現(xiàn)了元數(shù)據(jù)對象,然后將根據(jù)將Value值賦值給Name所對應的屬性名稱。

這么做雖然比較簡單,但是它有兩個弊端:

  • 1. 屬性名稱不是強類型

這里我們必須字符串來給標志屬性名稱,它們之間并沒有語法級的一致性檢查,在缺少nameof運算符的現(xiàn)在,一旦元數(shù)據(jù)屬性名稱更改的話是非常容易出錯的。

  • 2. 如果元數(shù)據(jù)有多個值的話賦值顯得非常累贅。

假如我們增加了一個Priority類型的屬性,

    public interface ILoggerData
    {
        string Name { get; }
        int Priority { get; }
    }

此時,必須對所有的導出對象都增加一個ExportMetadata標記,寫出如下形式:

    [ExportMetadata("Name", "DB Logger")]
    [ExportMetadata("Priority", 3)]

當屬性更多一點的話相信程序員們就會罵娘了。并且一旦某個Export對象漏寫了,改對象就不會被導入。這個是一個運行時的錯誤,非常不容易排查的。

通過Attribute標記

這種方式可以通過一個Attribute來標記元數(shù)據(jù):

    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
    class LoggerDataAttribute : Attribute, ILoggerData
    {
        public string Name { get; private set; }

        public LoggerDataAttribute(string name)
        {
            this.Name = name;
        }
    }

    [LoggerData("Console Logger")]
    [Export(typeof(ILogger))]
    class ConsoleLogger : ILogger, ILoggerData
    {
        public string Name { get; set; }

        public void Log(string message)
        {
            Console.WriteLine(message);
        }
    }

    [LoggerData("DB Logger")]
    [Export(typeof(ILogger))]
    class DbLogger : ILogger, ILoggerData
    {
        public string Name { get; set; }
        public void Log(string message)
        {
            Console.WriteLine(message);
        }
    }

首先,聲明一個LoggerDataAttribute,這個Attribute必須被MetadataAttribute標記。然后,在Export的對象前加上該LoggerDataAttribute,這樣MEF導入的時候就會根據(jù)該LoggerDataAttribute創(chuàng)建元數(shù)據(jù)了。

值得一提的是,這里的LoggerDataAttribute本身并不需要實現(xiàn)ILoggerData接口,它是一個DuckType的約定,只需要實現(xiàn)元數(shù)據(jù)的屬性即可。我這里實現(xiàn)該接口主要是為了讓編譯器保障元數(shù)據(jù)屬性都有被準確實現(xiàn)。

到此這篇關于C#在MEF框架中實現(xiàn)延遲加載部件的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • WPF下如何自定義MessageBox消息提示

    WPF下如何自定義MessageBox消息提示

    這篇文章主要介紹了WPF下如何自定義MessageBox消息提示問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • C#中的委托使用

    C#中的委托使用

    委托是C#中新加入的一個類型,可以把它想作一個和Class類似的一種類型,和使用類相似,使用一個委托時,需要兩個步驟,首先你要定義一個委托,就像是定義一個類一樣;然后,你可以創(chuàng)建一個或多個該委托的實例。
    2016-07-07
  • C#實現(xiàn)的json序列化和反序列化代碼實例

    C#實現(xiàn)的json序列化和反序列化代碼實例

    這篇文章主要介紹了C#實現(xiàn)的json序列化和反序列化代碼實例,本文講解了兩種實現(xiàn)方法,并直接給出代碼示例,需要的朋友可以參考下
    2015-06-06
  • C#實現(xiàn)注冊碼注冊機制效果詳解

    C#實現(xiàn)注冊碼注冊機制效果詳解

    這篇文章主要為大家詳細介紹了C#如何實現(xiàn)注冊碼注冊機制效果,文中的示例代碼講解詳細,對我們學習C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-01-01
  • C# Email郵件發(fā)送功能 找回或重置密碼功能

    C# Email郵件發(fā)送功能 找回或重置密碼功能

    這篇文章主要為大家詳細介紹了C# Email郵件發(fā)送功能,找回或重置密碼功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • C#中Hash table的一些操作方法講解

    C#中Hash table的一些操作方法講解

    今天小編就為大家分享一篇關于C#中Hash table的一些操作方法講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • 談C# using的用法與好處

    談C# using的用法與好處

    這篇文章主要為大家詳細介紹了C# using的用法與好處,具體分析了using指令調(diào)用的Dispose()方法,感興趣的朋友可以參考一下
    2016-05-05
  • C#多線程學習之Thread、ThreadPool、Task、Parallel四者區(qū)別

    C#多線程學習之Thread、ThreadPool、Task、Parallel四者區(qū)別

    這篇文章主要以一些簡單的小例子,簡述多線程的發(fā)展歷程:Thread,ThreadPool,Task,Parallel。文中的示例代碼講解詳細,對我們學習C#多線程有一定幫助,需要的朋友可以參考一下
    2021-12-12
  • C#實現(xiàn)定時任務Task Scheduler的示例代碼

    C#實現(xiàn)定時任務Task Scheduler的示例代碼

    這篇文章主要為大家詳細介紹了C#實現(xiàn)定時任務Task Scheduler的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-02-02
  • C#實現(xiàn)文件分割和合并的示例詳解

    C#實現(xiàn)文件分割和合并的示例詳解

    這篇文章主要為大家詳細介紹了如何利用C#實現(xiàn)文件分割和合并的功能,文中的示例代碼講解詳細,對我們學習C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12

最新評論