久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

MEF 打造的插件系統(tǒng)

 賈朋亮博客 2014-04-14

以實(shí)例說話,,一起體驗(yàn)MEF帶來的可擴(kuò)展性吧,Let’s Rock?。,。?/font>

 

1:新建控制臺(tái)程序SimpleCalculator

image

在這里要實(shí)現(xiàn)的程序時(shí)SimpleCalculator,,顧名思義:簡單的計(jì)算器,。

所以我們需要定義一個(gè)用來計(jì)算的接口:

public interface ICalculator

{

    String Calculate(String input);

}

 

Program 的代碼如下:

class Program
{
    private CompositionContainer _container;

    [Import(typeof(ICalculator))]
    private ICalculator calculator;

    public Program()
    {
        //var catalog = new AggregateCatalog();
        //catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

        var catalog = new AssemblyCatalog(typeof(Program).Assembly);
        _container = new CompositionContainer(catalog);

        try
        {
            this._container.ComposeParts(this);
        }
        catch (CompositionException compositionException)
        {
            Console.WriteLine(compositionException.ToString());
        }
    }

    static void Main(string[] args)
    {
        Program p = new Program();
        string s;
        Console.WriteLine("Enter Command:");

        while (true)
        {
            s = Console.ReadLine();
            Console.WriteLine(p.calculator.Calculate(s));
        }
    }
}

MEF所要解決的是尋找插件的功能,傳統(tǒng)的實(shí)現(xiàn)插件的方式主要是使用接口,,即聲明一個(gè)接口,,然后使用配置文件來配置接口使用哪個(gè)實(shí)現(xiàn)類。

 

微軟知道有這種需求,,于是提供了MEF來實(shí)現(xiàn)插件的功能,。

 

Composite 原理

1:聲明一個(gè) CompositionContainer 對(duì)象,這個(gè)對(duì)象里面包含一堆Catalog.

2:這堆Catalog如果是AssemblyCatalog,,則在Assembly中查找,,如果是DirectoryCatalog,

Directory 中查找,如果即想要在Assembly中查找,,又需要在Directory中查找,,

則采用AggregateCatalog

3:然后在這堆Catalog中查找與Import 特性相對(duì)應(yīng)的Export標(biāo)記所標(biāo)記的實(shí)現(xiàn)類,,調(diào)用實(shí)現(xiàn)類的構(gòu)造函數(shù)進(jìn)行

Composite(組合),。

知道原理后,你也可以自己實(shí)現(xiàn)自己的CompositionContainer 類了,,

 

要使用MEF 需要為SimpleCalculator添加 System.ComponentModel.Composition.dll 的引用,,

然后導(dǎo)入命名空間:

using System.ComponentModel.Composition;

using System.ComponentModel.Composition.Hosting;

接下來看下Program 的構(gòu)造函數(shù)所做的事情:

 

聲明一個(gè)AssemblyCatalog,指向Program所在的Assembly. 然后把它添加到

CompositionContainer中,調(diào)用CompositionContainer ComposeParts 擴(kuò)展方法,,來Compose(this) Parts,。

 

注:ComposeParts 是擴(kuò)展方法,需要using System.ComponentModel.Composition;

 

OK,,如何Compose,,在哪個(gè)Assembly中查找實(shí)現(xiàn)類來進(jìn)行Compose已經(jīng)完成了。

目前的問題是:哪些類需要Compose,?,?

 

為了回答這個(gè)問題,微軟提供了ImportExport特性: 

Import:哪個(gè)對(duì)象需要Compose,。也就是需要被實(shí)現(xiàn)類給填充,所以Import標(biāo)記的是對(duì)象,,一般該對(duì)象是接口,,因?yàn)槿绻蔷唧w類的話,那還需要Import嗎,?

Export:哪個(gè)類可以被用來Compose,也就是說這個(gè)類是不是可以用來填充的實(shí)現(xiàn)類,,所以Export標(biāo)記的是類,而不是具體的某個(gè)對(duì)象,。

 

所以在這里calculator 使用Import 特性來標(biāo)記:

[Import(typeof(ICalculator))]

private ICalculator calculator;

 

接下來MEF 的組合引擎在ComposeParts(this)的時(shí)候,,就會(huì)在catalog 代表的AssemblyCatalog中查找Export特性所修飾的實(shí)現(xiàn)類了,找到實(shí)現(xiàn)類后進(jìn)行Compose,。

 

如果找不到Export特性修飾的類的話,結(jié)果如下:

image

OK,,接下來添加一個(gè)實(shí)現(xiàn)類,,并使用Export特性來進(jìn)行修飾:

[Export(typeof(ICalculator))]

 public class MySimpleCalculator : ICalculator

 {

     public string Calculate(string input)

     {

         return "MySimpleCalculator 處理了" + input;

     }

 }

 

運(yùn)行結(jié)果如下:

image

當(dāng)然ImportExport還提供了其他的構(gòu)造函數(shù),所以你還可以將上面的ImportExport修改為:

[Import("calculator1", typeof(ICalculator))]

[Export("calculator1", typeof(ICalculator))]

 

之所以提供ContractNamecalculator1 是因?yàn)槟憧赡苡卸鄠€(gè)ICalculator對(duì)象需要填充,。

 

修改Program的代碼如下:

class Program

{

    private CompositionContainer _container;

 

    [Import("calculator1", typeof(ICalculator))]

    private ICalculator calculator1;

 

    [Import("calculator2", typeof(ICalculator))]

    private ICalculator calculator2;

 

    public Program()

    {

        //var catalog = new AggregateCatalog();

        //catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

 

        var catalog = new AssemblyCatalog(typeof(Program).Assembly);

        _container = new CompositionContainer(catalog);

 

        try

        {

            this._container.ComposeParts(this);

        }

        catch(CompositionException compositionException)

        {

            Console.WriteLine(compositionException.ToString());

        }

    }

 

    static void Main(string[] args)

    {

        Program p = new Program();

        string s;

        Console.WriteLine("Enter Command:");

 

        while (true)

        {

            s = Console.ReadLine();

            Console.WriteLine(p.calculator1.Calculate(s));

            Console.WriteLine(p.calculator2.Calculate(s));

        }

    }

}

 

修改Export修飾的類為:

[Export("calculator1", typeof(ICalculator))]

public class MySimpleCalculator1 : ICalculator

{

    public string Calculate(string input)

    {

        return "第一個(gè)Calculator 處理了" + input;

    }

}

 

[Export("calculator2", typeof(ICalculator))]

public class MySimpleCalculator2 : ICalculator

{

    public string Calculate(string input)

    {

        return "第二個(gè)Calculator 處理了" + input;

    }

}

 

運(yùn)行結(jié)果如下:

image

 

因?yàn)镮mport和Export是一一對(duì)應(yīng)的,,在現(xiàn)實(shí)世界中,存在著大量一對(duì)多的情況,,微軟也預(yù)料到了這種情況,,所以提供了ImportMany 特性。

 

在上個(gè)例子中的MySimpleCalculatorCalculate方法返回的是一句話,,在這個(gè)例子中要真正實(shí)現(xiàn)計(jì)算的功能,,例如輸入5+3,輸出8,,輸入7*4,,輸出28

 

為了支持 + - * / 四種Operation.所以在MySimpleCalculator中聲明一個(gè)operations 的列表,。

[Export(typeof(ICalculator))]

class MySimpleCalculator : ICalculator

{

    [ImportMany]

    IEnumerable<Lazy<IOperation, IOperationData>> operations;

 

    public string Calculate(string input)

        {

return "calculate 處理了" + input;

        }

}

 

之所以在MySimpleCalculator 中聲明operations ,,是因?yàn)槭怯?jì)算器支持多種運(yùn)算。因?yàn)?/span>operations 需要多個(gè)operation Compose(填充),所以使用ImportMany特性來修飾,,和Import特性一樣,,ImportMany特性一般也是修飾接口。

 

Ioperation IOperationData的定義如下:

 

public interface IOperation

{

    int Operate(int left, int right);

}

 

public interface IOperationData

{

    Char Symbol { get; }

}

 

Lazy<IOperation, IOperationData> operations:

提供對(duì)對(duì)象及其關(guān)聯(lián)的元數(shù)據(jù)的延遲間接引用,,以供 Managed Extensibility Framework 使用,。

意思是說IOperation IOperationData之間的引用需要延遲,為什么需要延遲,?,,因?yàn)?/span>IOperation需要根據(jù)IOperationDataSymbol符號(hào)來延遲創(chuàng)建。

也就是說,,如果IOperationDataSymbol 等于 “+”,那么IOperation對(duì)象是AddOperation.如果IOperationDataSymbol等于”-”,那么IOperation對(duì)象是SubtractOperation.

那么如何保證這點(diǎn)呢,?

 

關(guān)鍵點(diǎn)就在于ExportMetadata attribute 上,。

看下Add Operation 的定義:

 

[Export(typeof(IOperation))]

[ExportMetadata("Symbol", '+')]

class Add : IOperation

{

    public int Operate(int left, int right)

    {

        return left + right;

    }

}

 

在這里ExportMetadata特性的Symbol +。所以當(dāng)IOperationDataSymbol”+” 的時(shí)候,,匹配的就是Add Operation

 

MySimpleCalculator 的完整代碼如下:

 

[Export(typeof(ICalculator))]

class MySimpleCalculator : ICalculator

{

    [ImportMany]

    IEnumerable<Lazy<IOperation, IOperationData>> operations;

 

    public string Calculate(string input)

        {

            int left;

            int right;

 

            char operation;

 

            int fn = FindFirstNonDigitPosition(input);

 

            if (fn < 0) return "Could not parse command.";

 

            try

            {

                left = int.Parse(input.Substring(0, fn));

                right = int.Parse(input.Substring(fn + 1));

            }

            catch

            {

                return "Could not parse command";

            }

 

            operation = input[fn];

 

            foreach (Lazy<IOperation, IOperationData> i in operations)

            {

                if (i.Metadata.Symbol.Equals(operation))

                    return i.Value.Operate(left, right).ToString();

            }

 

            return "Operation Not Found!";

        }

 

    private int FindFirstNonDigitPosition(string s)

    {

        for (int i = 0; i < s.Length; i++)

        {

            if (!(Char.IsDigit(s[i]))) return i;

        }

        return -1;

    }

}

 

回頭再看看上例的Program代碼:

class Program

{

    private CompositionContainer _container;

 

    [Import(typeof(ICalculator))]

    private ICalculator calculator;

 

    public Program()

    {

        //var catalog = new AggregateCatalog();

        //catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

 

        var catalog = new AssemblyCatalog(typeof(Program).Assembly);

 

        _container = new CompositionContainer(catalog);

 

        try

        {

            this._container.ComposeParts(this);

        }

        catch(CompositionException compositionException)

        {

            Console.WriteLine(compositionException.ToString());

        }

    }

 

    static void Main(string[] args)

    {

        Program p = new Program();

        string s;

        Console.WriteLine("Enter Command:");

 

        while (true)

        {

            s = Console.ReadLine();

            Console.WriteLine(p.calculator.Calculate(s));

        }

    }

}

 

 

當(dāng)this._container.ComposeParts(this); 的時(shí)候,,MEF組合引擎就開始對(duì)標(biāo)記了Import特性的接口進(jìn)行Compose,所以在這里是calculator,。在哪里找實(shí)現(xiàn)類呢,?,AssemblyCatalog表明在Program的當(dāng)前Assembly中查找實(shí)現(xiàn)類,,所以找到了MySimpleCalculator在構(gòu)造MySimpleCalculator 的時(shí)候,,發(fā)現(xiàn)了ImportMany特性修飾的operations。于是繼續(xù)在AssemblyCatalog中找到了Add,。

 

上面的過程是Compose的過程,。

那么MySimpleCalculator 如何進(jìn)行Calculate的呢?

例如5+3

1:找出第一個(gè)非數(shù)字的位置,,也就是需要找出 +,。

2:聲明left,right.并且left 5right3.

3:根據(jù)符號(hào)+來構(gòu)造IOperation對(duì)象,,接著調(diào)用IOperation對(duì)象的Operate(left,right)方法,。

foreach (Lazy<IOperation, IOperationData> i in operations)

 {

     if (i.Metadata.Symbol.Equals(operation))

         return i.Value.Operate(left, right).ToString();

 }

 

運(yùn)行結(jié)果:

image

因?yàn)槟壳岸x了Add Operation。所以根據(jù)符號(hào)+ 能夠找到Add,,但是*我們沒有定義,,所以Operation Not Found!.

 

于是開始定義Multiple:

[Export(typeof(IOperation))]

 [ExportMetadata("Symbol", '*')]

 class Multiple : IOperation

 {

     public int Operate(int left, int right)

     {

         return left * right;

     }

 }

 

再次運(yùn)行,結(jié)果如下:

image

 

當(dāng)然還可以在當(dāng)前程序集下面增加- ,/,^,% Operation,。

 

為了讓事情更加的有趣,,我打算在Debug目錄下增加一個(gè)目錄CalculateExtensions,然后將-,/ ..Operation放到里面來,,讓MEF自動(dòng)發(fā)現(xiàn),。

image

 

首先新建類庫項(xiàng)目:SimpleCalculatorExtension

因?yàn)樾枰獙?shí)現(xiàn)IOperation ,所以需要添加對(duì)SimpleCalculator項(xiàng)目的引用,。

因?yàn)樾枰?/span>Export特性,,所以需要添加對(duì)System.ComponentModel.Composition的引用。

整個(gè)項(xiàng)目的結(jié)果如下:

image

 

Subtract代碼如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ComponentModel.Composition;

 

namespace SimpleCalculatorExtension

{

    [Export(typeof(SimpleCalculator.IOperation))]

    [ExportMetadata("Symbol", '-')]

    class Subtract : SimpleCalculator.IOperation

    {

        public int Operate(int left, int right)

        {

            return left - right;

        }

    }

}

 

生成成功后,,將SimpleCalculatorExtension.dll 拷貝到CalculateExtensions目錄下:

現(xiàn)在SimpleCalculatorDebug目錄應(yīng)該是這樣,。

image

 

并且CalculateExtensions文件夾下面有SimpleCalculatorExtension.dll.

 

接下來唯一要修改的是Programcatalog 對(duì)象。

為了讓catalog既支持在ProgramAssembly中查找,,又支持在CalculateExtensions目錄下查找,。修改代碼如下:

public Program()

 {

     var catalog = new AggregateCatalog();

     catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

     catalog.Catalogs.Add(new DirectoryCatalog("CalculateExtensions"));

 

     _container = new CompositionContainer(catalog);

 

     try

     {

         this._container.ComposeParts(this);

     }

     catch(CompositionException compositionException)

     {

         Console.WriteLine(compositionException.ToString());

     }

 }

 

運(yùn)行結(jié)果如下:

image

 

修改SimpleCalculatorExtension Subtract方法為:

namespace SimpleCalculatorExtension

{

    [Export(typeof(SimpleCalculator.IOperation))]

    [ExportMetadata("Symbol", '-')]

    class Subtract : SimpleCalculator.IOperation

    {

        public int Operate(int left, int right)

        {

            Console.WriteLine("SimpleCalculatorExtension的方法");

            return left - right;

        }

    }

}

重新生成SimpleCalculatorExtension.dll 然后拷貝到CalculateExtensions 文件夾下:

再次運(yùn)行程序,輸出入下:

image

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多