中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#在MEF框架中怎么實現延遲加載部件

發布時間:2022-06-23 13:43:16 來源:億速云 閱讀:180 作者:iii 欄目:開發技術

這篇文章主要介紹“C#在MEF框架中怎么實現延遲加載部件”,在日常操作中,相信很多人在C#在MEF框架中怎么實現延遲加載部件問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”C#在MEF框架中怎么實現延遲加載部件”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

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

    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);

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

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

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

    [Import]
    Lazy<ILogger> _logger = null;

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

元數據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);

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

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

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

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

    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");
        }
    }

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

現在的問題是:如何在導出的時候聲明相關的元數據。MEF提供了兩種方式:

通過ExportMetadataAttribute標記聲明

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

    [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有兩個參數,Name和Value,Name為屬性名稱,Value為屬性值。Compse的時候,MEF會先創建一個實現了元數據對象,然后將根據將Value值賦值給Name所對應的屬性名稱。

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

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

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

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

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

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

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

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

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

通過Attribute標記

這種方式可以通過一個Attribute來標記元數據:

    [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導入的時候就會根據該LoggerDataAttribute創建元數據了。

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

到此,關于“C#在MEF框架中怎么實現延遲加載部件”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

mef
AI

井研县| 深水埗区| 淮南市| 平江县| 望谟县| 上栗县| 读书| 江门市| 突泉县| 陆良县| 蒲江县| 锦州市| 南乐县| 伊宁县| 嘉兴市| 合江县| 仪陇县| 卫辉市| 从化市| 延川县| 左权县| 盘锦市| 哈尔滨市| 海南省| 巴东县| 南川市| 绵竹市| 德阳市| 永泰县| 苍溪县| 通河县| 雷山县| 昆明市| 九龙县| 扬州市| 荃湾区| 即墨市| 宜兰县| 徐闻县| 庆安县| 鲁山县|