MEF 插件式開發 - 小試牛刀

来源:https://www.cnblogs.com/hippieZhou/archive/2018/08/01/9398354.html
-Advertisement-
Play Games

[TOC] MEF 簡介 Managed Extensibility Framework 即 MEF 是用於創建輕量、可擴展應用程式的庫。 它讓應用程式開發人員得以發現和使用擴展且無需配置。 它還讓擴展開發人員得以輕鬆地封裝代碼並避免脆弱的緊密依賴性。 MEF 讓擴展不僅可在應用程式內重覆使用,還可 ...


目錄


MEF 簡介

Managed Extensibility Framework 即 MEF 是用於創建輕量、可擴展應用程式的庫。 它讓應用程式開發人員得以發現和使用擴展且無需配置。 它還讓擴展開發人員得以輕鬆地封裝代碼並避免脆弱的緊密依賴性。 MEF 讓擴展不僅可在應用程式內重覆使用,還可以跨程式重覆使用。

在進行傳統的 C/S 端開發,如果項目不是特別複雜,常規的開發模式還是可以應對的。但是一旦場景複雜度提升,一個小小業務功能的修改就需要更新整個客戶端,這個對於開發者來說是不能忍受的。因此微軟為我們引入了 MEF 的開發模式。允許我們將眾多的業務模塊拆分開來設計成獨立的 DLL,然後由客戶端來進行統一載入,這樣就能解決上述我們所說的痛點。

實踐出真知

創建一個高擴張的 MEF 框架涉及的技術點較多。為了方便初學者能較快理解,上手實踐,我這裡主要通過 3 個方面來進行相關敘述。

面向介面編程

如果你還不能理解什麼是面向介面編程的話,那你應該還不能區分抽象類和介面之間的區別。其實在剛開始的時候我也不是很能理解,直到我看到了一句話:抽象類規定了你是什麼,介面規定了你能幹什麼,只要你能理解這句話,那麼你應該就明白什麼是面向介面編程,這種編程方式的好處是統一化了業務的暴露方式,方便外部使用。下麵我們看一個簡單的例子。

public interface IMessage
{
    void Send();
}

public class EmailService : IMessage
{
    public void Send()
    {
        Console.WriteLine("Email Send Message");
    }
}

public class SMSService : IMessage
{
    public void Send()
    {
        Console.WriteLine("SMS Send Message");
    }
}

class Program
{
    static void Main(string[] args)
    {
        IMessage email = new EmailService();
        email.Send();

        IMessage sms = new SMSService();
        sms.Send();

        Console.ReadKey();
    }
}

上述代碼中,我們創建了一個 IPlugin 的介面,介面定義了一個 ShowPluginName() 方法,然後我們再定義了兩個獨立的類來分別繼承該介面並實現相應的介面函數。在主函數中,我們只需要定義一個介面類型的對象,然後接收一個具體的類型實例,函數就會輸出對應的正確信息。這樣編程的好處就不言而喻了。代碼很簡單,這裡就不過多描述。輸出結果如下圖所示


控制反轉(IOC)

所謂控制反轉,就是將對象初始化的控制權交出去。要實現控制反轉,我們需要有面向介面編程的介面,同樣的,這裡也是展示一個代碼段來敘述。

public interface IMessage
{
    void Send();
}

public class EmailService : IMessage
{
    public void Send()
    {
        Console.WriteLine("Email Send Message");
    }
}

public class SMSService : IMessage
{
    public void Send()
    {
        Console.WriteLine("SMS Send Message");
    }
}

public static class Factory
{
    public static EmailService GetEmailService() => new EmailService();

    public static SMSService GetSMSService() => new SMSService();
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("DependencyService:");
        DependencyService();

        Console.WriteLine();

        Console.WriteLine("InversionDependencyService:");
        InversionDependencyService();

        Console.ReadKey();
    }

    static void DependencyService()
    {
        EmailService fooEmailService = new EmailService();
        fooEmailService.Send();
    }
    static void InversionDependencyService()
    {
        IMessage fooMessage = Factory.GetEmailService();
        fooMessage.Send();
        fooMessage = Factory.GetSMSService();
        fooMessage.Send();
    }
}

在這個例子中,我們通過工廠模式創建具體的服務,然後供主程式來調用,代碼依然很簡單,分別用傳統創建服務的方式和 控制反轉的方式來進行對比。程式輸出如下


構建入門級 MEF

有了上面兩個知識點做鋪墊,我們可以開始創建一個入門級的 MEF 示常式序。想要在程式中使用 MEF 的話需要引入如下程式集

  • System.ComponentModel.Composition

這裡還是以控制台程式來展示。項目結構如下圖所示


  • MefSample.Core:核心介面定義在該項目中
  • MefSample.EmailService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
  • MefSample.SMSService:插件,需要引用 MefSample.Core 和 System.ComponentModel.Composition
  • MefSample:主程式,需要引用 MefSample.Core 和 System.ComponentModel.Composition

註意:上述所有項目程式的輸出目錄需要保持一致

MefSample.Core 代碼段

public interface IMessage
{
    void Send();
}

MefSample.EmailService 代碼段

[Export(typeof(IMessage))]
public class EmailService: IMessage
{
    public void Send()
    {
        Console.WriteLine("Email Send Message");
    }
}

MefSample.SMSService 代碼段

[Export(typeof(IMessage))]
public class SMSService : IMessage
{
    public void Send()
    {
        Console.WriteLine("SMS Send Message");
    }
}

MefSample 代碼段

class Program
{
    static void Main(string[] args)
    {
        var dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
        var catalog = new DirectoryCatalog(dir.FullName, "*.dll");
        using (CompositionContainer container = new CompositionContainer(catalog))
        {
            IEnumerable<IMessage> messages = container.GetExportedValues<IMessage>();
            if (messages != null)
            {
                foreach (var message in messages)
                {
                    message.Send();
                }
            }
        }
        Console.ReadKey();
    }
}

仔細觀察的話,其實上述代碼還是挺簡單的, 我這裡使用了 DirectoryCatalog 的方式來尋找目標插件,感興趣的朋友可以試試其他方式:AggregateCatalogAssemblyCatalogDirectoryCatalog。當然,你也可以自定義。程式輸出結果如下圖所示


好了,程式寫到這裡相信你對 MEF 也多少有些瞭解。我沒有過多的講解抽象理論,而是更多地通過代碼來描述我所想要說的。在下篇文章中,我將會簡單講述一下 MEF 在 WPF 中的入門使用,方便初學者更上一層樓。加油,共勉!

相關參考


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 概述 OLE,Object Linking and Embedding,即對象連接與嵌入。我們在設計程式時,OLE可以用來創建複合文檔,把文字、聲音、圖像、表格、應用程式等類型的信息組合在一起,在Word中,我們可以通過OLE來實現以上要素信息的組合。下麵的示例中將介紹如何通過C# 來操作Word中 ...
  • 簡介 繼承(封裝、多態)是面向對象編程三大特性之一,繼承的思想就是擯棄代碼的冗餘,實現更好的重用性。 繼承從字面上理解,無外乎讓人想到某人繼承某人的某些東西,一個給一個拿。這個語義在生活中,就像 家族繼承財產,爺爺將財產繼承給兒女,兒女在將財產繼承給子孫,有些東西可以繼承有些的東西只繼承給 某人。映 ...
  • 1.今天在部署IIS7應用程式的時候出現了這個錯誤,本以為是發佈的錯誤,其實不然,是IIS中所依賴的項沒有配置正確 2.選擇創建站點中對應的應用池 高級設置 啟用32位應用程式,然後把值改為true。 3.打開cmd命令進行安裝 如果映射存在,請檢查應用程式是否分配給了.NET Framework4 ...
  • 摘要:接下來的幾篇博客將要講到如何使用ado.net實現簡單的資料庫操作,包括增刪改等內容。首先會介紹基礎的資料庫操作,然後以一個實例來進行講解,這個實例會把一個數據表讀取到winform上,然後在winform上有一些按鈕和文本框,通過這些實現對資料庫里的內容的增刪改的操作。我個人比較菜,因此記錄... ...
  • 效果如下: 鄙人雖然開發WPF有些時間,但之前一直是一些簡單Template和Style改改之類的工作,並沒有深入研究過。此次為了完成工作,首先也是網上搜了半天,沒有找到合適的代碼直接拷貝(搜索能力待提高),乾脆就直接靜下心來琢磨琢磨。 一開始在界面上就放了Slider,撓撓頭,怎麼修改Templa ...
  • 為什麼文章要添加內鏈? 1.有利於讀者 我喜歡內鏈文章的最初動機是讓讀者在我的博客獲得更好的閱讀體驗,並獲得更多的價值。如果我的讀者訪問了我的一篇文章,發現不僅僅回答他需要的答案,還提供了更多相關內容的信息,讓他們能在更多的相關主題去擴展閱讀,他們遲早會喜歡並滿意我的博客。讓讀者滿意就是我們的目標, ...
  • 工作中長期需要用到通過HTTP調用API以及文件上傳下載,積累了不少經驗,現在將各種不同方式進行一個彙總。 首先是HttpWebRequest: 然後是HttpWebResponse: 上面兩個方法需要配合使用,皆為同步方式。當然也可以將上面兩個方法合併到一個方法中,可以參見接下來這個方法。 另外是 ...
  • 使用EF flument API 修改映射資料庫欄位的自增長 modelBuilder.Entity<Invoice>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); 報錯Method n ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...