【.NET 深呼吸】在 .net core app 中使用 Composition

.NET 中的 Composition ,即 MEF。MEF 說得簡單一點,就是它能夠在運行階段動態地發現類型,用於組件擴展方面特別合適。app

.NET Core App 的默認框架並不提供 MEF 有關的 API,但,別忘了 Nuget,那上面有相關的庫,並且是官方發佈的,不出意外的話,是能用的,並且老周也親自測過,嚴重證明是可用的。框架

哦,是了,順便提一下,若是你弄的是 ASP.NET Core 項目,對於組件擴展,你能夠沒必要考慮用 Composition,由於 ASP.NET Core 有強大的依賴注入功能,因此,經過注入,也能作到動態發現組件的效果,並且集成性更好。spa

因此,因此嘛,我們今天說的 Composition 主要是針對 .net core app,默認模板提供的是控制檯應用程序,或者類庫。固然了,也多是其餘類型的項目,並且開源項目未來也會多起來。.net

 

好了,上面說的都是閒話,我們開始講正話。code

首先,你要先建一個 core 的項目,嗯,就選控制檯應用吧。component

建好項目以後,打開項目的 Nuget 管理器,搜索:對象

System.ComponentModel.Composition

注意,別搜錯了,由於 System.Composition 是挺多的,能搜出一打來,可是,你要細看,System.ComponentModel.Composition 支持 Core。請注視下面這張高清無碼截圖。blog

 

如今你明白爲啥要選這個了,至於說 System.Composition 是否支持在 .net core app 中使用,這個就不知道了,沒試,你有空的話能夠試試,但上面沒有註明支持 core。接口

而後安裝 System.ComponentModel.Composition 包,安裝到項目後,就能用了。來,趕忙試試。get

 

引入如下這兩個命名空間:

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

 

定義一個接口,做爲擴展組件的共同協定。

    public interface IMovie
    {
        void Play();
    }

它表示某電影院正在上映的電影。

下面兩家影院(組件)近期比較熱門。

    public class NewMovie : IMovie
    {
        public void Play()
        {
            Console.WriteLine("此處正在放映《我不是酒神》");
        }
    }

    public class NanMovie : IMovie
    {
        public void Play()
        {
            Console.WriteLine("此處正在放映《三烤白骨精》");
        }
    }

其實這樣定義的組件,在運行時仍是不能被發現的,咱們得讓它們導出。方法是……本身看下面代碼。

 [Export(typeof(IMovie))] public class NewMovie : IMovie
    {
        public void Play()
        {
            Console.WriteLine("此處正在放映《我不是酒神》");
        }
    }

    [Export(typeof(IMovie))] public class NanMovie : IMovie
    {
        public void Play()
        {
            Console.WriteLine("此處正在放映《三烤白骨精》");
        }
    }

導出約束有這麼幾種:

* 約束類型,這通常是組件的約定接口,就是組件實現的共同接口,好比上面的 IMovie。

* 約束名,這個嘛,本身賜給它一個名字便可。

* 混合,就是約束名 + 約束類型。這種方法最爲準確,在導入時能夠準確找到組件。

若是 ExportAttribute 應用的目標是組件類,而不是接口類型,這時你至少得手動指定一個約束類型,設置爲 IMovie,否則,它默認就是目標類的名字,這樣一來,這兩個組件就沒法保有共同的約束,導入時不容易找出來。

我爲了演示方便,我這些組件的定義與使用都是在同一個程序集中,因此,組件查找範圍在當前程序集中。

            // 獲取當前程序集
            Assembly assCurr = Assembly.GetExecutingAssembly();
            // 肯定組件搜索範圍
            AssemblyCatalog catalog = new AssemblyCatalog(assCurr);

用上面準備好的 Catalog 去初始化 CompositionContainer ,經過容器去獲取發現的組件實例。

            using(CompositionContainer container = new CompositionContainer(catalog))
            {
                // 獲取已發現的組件
                var components = container.GetExportedValues<IMovie>();             }

GetExportedValues 方法能直接獲得全部發現的組件的實例,若是不想立刻用到組件實例,能夠獲取 Lazy 包裝的對象,延時初始化,方法是調用 GetExports 或者 GetExport 方法。

獲得全部組件實例後,能夠嘗試調用一下。

            using(CompositionContainer container = new CompositionContainer(catalog))
            {
                // 獲取已發現的組件
                var components = container.GetExportedValues<IMovie>();
                // 分別調用一下
               foreach(IMovie m in components) { m.Play(); }             }

 

程序運行後,就會輸出如下內容。

 

看,兩個組件都被成功調用了。

 

========================================================================

 最近腦細胞不夠用,因此博客寫得少了,老周在此表示歉意。等過一段時間,腦細胞復活了,老周有空就多寫些簡單實用的博文。複雜而不實用的東西老周不太會寫,唉,無法了,畢竟老周的水平也比較菜,沒見過大世面,沒作過大項目,沒調過大 bug。最大的項目也就是 1213 個實體類,200 多個存儲過程,900 多個表,120 個視圖。這種規模,估計是老周這一輩子作過的最大的項目了。

相關文章
相關標籤/搜索