插件化編程實現的一份糖炒栗子~~

迷茫的原因是因為想得太多,做得太少。因為只是 想 真的很容易,轉瞬之間就會產生無數個念頭,或許是該做點什么了吧。

但是整個人都是懶的,是廢的,是大腦控制不住自己的行為的。解決方案唯有一步一步的去把行為變成習慣。

堅持一件事挺不容易的,不論結果的好壞,過程中總有收獲的,堅持,不會是一件壞事。

胡言亂語結束~~~

下面是記錄分享的一點東西~~請笑納

0.結構一覽

  

1.定義插件接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace YimoCore
{public interface IPlugin{/// <summary>/// Gets or sets the plugin descriptor/// </summary>PluginDescriptor PluginDescriptor { get; set; }/// <summary>/// Install plugin/// </summary>void Install();/// <summary>/// Uninstall plugin/// </summary>void Uninstall();}
}
定義插件

2.添加插件信息類

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;namespace YimoCore
{/// <summary>/// 插件信息/// </summary>public sealed class PluginDescriptor{/// <summary>/// 插件主目錄/// </summary>public string PluginFileName { get; set; }/// <summary>/// 插件類型/// </summary>public Type PluginType { get; set; }/// <summary>/// 插件主程序集/// </summary>public Assembly ReferencedAssembly { get; internal set; }/// <summary>/// 原始程序集文件/// </summary>public FileInfo OriginalAssemblyFile { get; internal set; }/// <summary>/// 插件包目錄/// </summary>public FileInfo PluginConfigFile { get; internal set; }/// <summary>/// 類別/// </summary>public string Group { get; set; }/// <summary>/// 插件名稱/// </summary>public string FriendlyName { get; set; }/// <summary>/// 程序集名稱/// </summary>public string SystemName { get; set; }/// <summary>/// 描述/// </summary>public string Description { get; set; }/// <summary>/// 版本號/// </summary>public string Version { get; set; }/// <summary>/// 支持版本/// </summary>public IList<string> SupportedVersions { get; set; }/// <summary>/// 作者/// </summary>public string Author { get; set; }/// <summary>/// 排序/// </summary>public int DisplayOrder { get; set; }/// <summary>/// 獲取插件實例/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public T Instance<T>() where T : class, IPlugin{var instance = Activator.CreateInstance(PluginType) as T;if (instance != null)instance.PluginDescriptor = this;return instance;}public IPlugin Instance(){return Instance<IPlugin>();}public int CompareTo(PluginDescriptor other){if (DisplayOrder != other.DisplayOrder)return DisplayOrder.CompareTo(other.DisplayOrder);elsereturn System.String.Compare(FriendlyName, other.FriendlyName, System.StringComparison.Ordinal);}public override string ToString(){return FriendlyName;}public override bool Equals(object obj){var other = obj as PluginDescriptor;return other != null &&SystemName != null &&SystemName.Equals(other.SystemName);}public override int GetHashCode(){return SystemName.GetHashCode();}}
}
插件信息類

3.插件讀取

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;namespace YimoCore
{public class PluginManager{private const string PluginsPath = "/modules"; //插件目錄private const string ShadowCopyPath = "/modules/bin"; //插件影子目錄public static IEnumerable<PluginDescriptor> ReferencedPlugins { get; set; }public static void Init(){var appdir = AppDomain.CurrentDomain.BaseDirectory.Substring(0, AppDomain.CurrentDomain.BaseDirectory.LastIndexOf("\\"));appdir = appdir.Substring(0, appdir.LastIndexOf("\\"));appdir = appdir.Substring(0, appdir.LastIndexOf("\\"));//插件目錄var pluginFolder = new DirectoryInfo(appdir + PluginsPath);//插件bin目錄var shadowFolder = new DirectoryInfo(appdir + ShadowCopyPath);var referencedPlugins = new List<PluginDescriptor>();try{pluginFolder.Create();shadowFolder.Create();//清空bin目錄foreach (var fileInfo in shadowFolder.GetFiles()){fileInfo.Delete();}var pluginConfigFiles = pluginFolder.GetFiles("about.xml", SearchOption.AllDirectories);foreach (var pluginConfigFile in pluginConfigFiles){//獲取插件信息var pluginDescriptor = PluginFileParser.ParsePluginDescriptionFile(pluginConfigFile.FullName);try{if (pluginConfigFile.Directory == null)continue;//獲取插件所有的dllvar pluginFiles = pluginConfigFile.Directory.GetFiles("*.dll", SearchOption.AllDirectories);var mainPluginFile = pluginFiles.FirstOrDefault(item =>item.Name.Equals(pluginDescriptor.PluginFileName,StringComparison.InvariantCultureIgnoreCase));pluginDescriptor.PluginConfigFile = pluginConfigFile;pluginDescriptor.OriginalAssemblyFile = mainPluginFile;pluginDescriptor.ReferencedAssembly = DeployDllFile(mainPluginFile, shadowFolder);foreach (var t in pluginDescriptor.ReferencedAssembly.GetTypes()){if (typeof(IPlugin).IsAssignableFrom(t)){if (t.IsInterface == false && t.IsClass && !t.IsAbstract){pluginDescriptor.PluginType = t;break;}}}referencedPlugins.Add(pluginDescriptor);}catch (ReflectionTypeLoadException ex){throw;}}}catch (ReflectionTypeLoadException ex){}ReferencedPlugins = referencedPlugins;}/// <summary>/// 部署程序集/// </summary>/// <param name="dllFile">插件程序集文件</param>/// <param name="shadowFolder">/Plugins/bin目錄</param>private static Assembly DeployDllFile(FileInfo dllFile, DirectoryInfo shadowFolder){DirectoryInfo copyFolder;//根據當前的信任級別設置復制目錄
copyFolder = shadowFolder;var newDllFile = new FileInfo(copyFolder.FullName + "\\" + dllFile.Name);try{File.Copy(dllFile.FullName, newDllFile.FullName, true);}catch (Exception ex1)//在某些情況下會出現"正由另一進程使用,因此該進程無法訪問該文件"錯誤,所以先重命名再復制
            {try{File.Move(newDllFile.FullName, newDllFile.FullName + Guid.NewGuid().ToString("N") + ".locked");}catch (Exception ex2){throw ex2;}File.Copy(dllFile.FullName, newDllFile.FullName, true);}var assembly = Assembly.LoadFrom(newDllFile.FullName);//將程序集添加到當前應用程序域//BuildManager.AddReferencedAssembly(assembly);return assembly;}}
}
插件讀取
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;namespace YimoCore
{/// <summary>/// Plugin files parser/// </summary>public static class PluginFileParser{public static IList<string> ParseInstalledPluginsFile(string filePath){if (!File.Exists(filePath))return new List<string>();var text = File.ReadAllText(filePath);if (String.IsNullOrEmpty(text))return new List<string>();var lines = new List<string>();using (var reader = new StringReader(text)){string str;while ((str = reader.ReadLine()) != null){if (String.IsNullOrWhiteSpace(str))continue;lines.Add(str.Trim());}}return lines;}public static void SaveInstalledPluginsFile(IList<String> pluginSystemNames, string filePath){if (pluginSystemNames == null || pluginSystemNames.Count == 0)return;string result = "";foreach (var sn in pluginSystemNames)result += string.Format("{0}{1}", sn, Environment.NewLine);File.WriteAllText(filePath, result);}public static PluginDescriptor ParsePluginDescriptionFile(string filePath){XDocument doc;try{doc = XDocument.Load(filePath);}catch (Exception){return null;}var pluginEle = doc.Element("plugin");if (pluginEle == null)return null;var descriptor = new PluginDescriptor();var ele = pluginEle.Element("SystemName");if (ele != null)descriptor.SystemName = ele.Value;ele = pluginEle.Element("Group");if (ele != null)descriptor.Group = ele.Value;ele = pluginEle.Element("FriendlyName");if (ele != null)descriptor.FriendlyName = ele.Value;ele = pluginEle.Element("Description");if (ele != null)descriptor.Description = ele.Value;ele = pluginEle.Element("Version");if (ele != null)descriptor.Version = ele.Value;ele = pluginEle.Element("SupportedVersions");if (ele != null){//parse supported versionsdescriptor.SupportedVersions = ele.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList();}ele = pluginEle.Element("Author");if (ele != null)descriptor.Author = ele.Value;ele = pluginEle.Element("DisplayOrder");if (ele != null){int displayOrder;int.TryParse(ele.Value, out displayOrder);descriptor.DisplayOrder = displayOrder;}ele = pluginEle.Element("FileName");if (ele != null)descriptor.PluginFileName = ele.Value;if (descriptor.SupportedVersions.Count == 0)descriptor.SupportedVersions.Add("2.00");return descriptor;}public static void SavePluginDescriptionFile(PluginDescriptor plugin){if (plugin == null)throw new ArgumentException("plugin");if (plugin.PluginConfigFile == null)throw new Exception(string.Format("沒有加載插件 {0} 的配置文件", plugin.SystemName));var doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),new XElement("Group", plugin.Group),new XElement("FriendlyName", plugin.FriendlyName),new XElement("SystemName", plugin.SystemName),new XElement("Description", plugin.Description),new XElement("Version", plugin.Version),new XElement("SupportedVersions", string.Join(",", plugin.SupportedVersions)),new XElement("Author", plugin.Author),new XElement("DisplayOrder", plugin.DisplayOrder),new XElement("FileName", plugin.PluginFileName));doc.Save(plugin.PluginConfigFile.FullName);}}
}
加載插件-PluginFileParser

?

4.使用

  4.0新建插件接口并繼承IPlugin

  

  4.1:為插件類庫添加about.xml文件配置插件信息

<?xml version="1.0" encoding="utf-8" ?>
<plugin><Group>Sign</Group><FriendlyName>素材網</FriendlyName><SystemName>素材網</SystemName><Description>素材網簽到</Description><Version>1.0</Version><SupportedVersions>1.0</SupportedVersions><Author>YiMo</Author><DisplayOrder>1</DisplayOrder><FileName>素材網.dll</FileName>
</plugin>
View Code

  4.2在插件類庫中實現ISign接口 (這里需要將PluginDescriptor字段實現)  

  

  4.3:修改插件所在類庫的生成事件 工具下載

  

  生成......

  4.4:生成解決方案后,就可以愉快的使用了

  

  

Over~~~完整Demo?代碼下載。?

?

最后附上使用上述方式寫的的一個簽到程序:https://github.com/yimogit/YimoCustomizedSign

?

現已經實現三個網站的的一鍵簽到。后續會實現更多網站的簽到功能等~~

跪求路過的大牛指點一二,也極度希望有人能和我一起來探討,優化,擴展這個小軟件和 更多更多更多的想法。

無論如何,每天都要進步一點點,基礎再牢一點,效率再高一點,代碼再風騷一點,生活再開心一點。每天只要一點點就好。

?

轉載于:https://www.cnblogs.com/morang/p/5630609.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372718.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372718.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372718.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用C#來學習唐詩三百首和全唐詩

Begin 最近把項目做完了&#xff0c;閑來無事&#xff0c;就想做點好玩的事情&#xff0c;剛好前幾天下載了【唐詩三百首】和【全唐詩】這兩個txt文件&#xff0c;正好用C#來整理一下。 然后導出QData格式&#xff0c;可以給其他軟件讀取。 以后弄個開機自動顯示一句詩&#xf…

JRockit JRCMD教程

本文將為您提供概述和教程&#xff0c;說明如何使用jrcmd工具對JRockit Java Heap問題進行初始分析和問題隔離。 將來的文章中將介紹使用JRockit任務控制和堆轉儲分析&#xff08;僅限JRockit R28 版&#xff09;的更深入的分析和教程。 有關JRockit Java堆空間的快速概述&…

sts java配置tomcat_STS配置Tomcat.9.0

今天&#xff0c;心血來潮&#xff0c;弄了一下STS,按著建立WEB項目的方式建立工程。一、新建工程(FILE --NEW--Dynamic Web project)二、輸入項目名稱&#xff0c;TestWeb&#xff0c;然后下一步&#xff0c;點擊FInish.三、新建index.jsp并打開index.jsp,書寫測試成功&#x…

javaweb國際化

根據數據的類型不同&#xff0c;國際化分為2類&#xff1a;靜態數據國際化和動態數據的國際化。 靜態數據&#xff0c;包括 “標題”、“用戶名”、“密碼”這樣的文字數據。 動態數據&#xff0c;包括日期、貨幣等可以動態生成的數據。 國際化涉及到java.util.Locale和java.ut…

20145335郝昊《網絡攻防》Bof逆向基礎——ShellCode注入與執行

20145335郝昊《網絡攻防》Bof逆向基礎——ShellCode注入與執行 實驗原理 關于ShellCode&#xff1a;ShellCode是一段代碼&#xff0c;作為數據發送給受攻擊服務器&#xff0c;是溢出程序和蠕蟲病毒的核心&#xff0c;一般可以獲取權限。我們將代碼存儲到對方的堆棧中&#xff0…

Java枚舉益智游戲

假設我們有以下代碼&#xff1a; enum Case {CASE_ONE,CASE_TWO,CASE_THREE;private static final int counter;private int valueDependsOnCounter;static {int sum 0;for(int i 0; i<10; i) {sum i;}counter sum;} Case() {this.valueDependsOnCounter counter*counte…

jp在java中無法編譯_JPanal上加圖片的問題!

JPanal上加圖片的問題&#xff01;import java.awt.BorderLayout;import java.awt.Dimension;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.*;import java.awt.*;public class Frame1 extends JFrame {JPanel contentPane;JLabel jLabel1 new JLa…

玩轉Android之加速度傳感器的使用,模仿微信搖一搖

Android系統帶的傳感器有很多種&#xff0c;最常見的莫過于微信的搖一搖了&#xff0c;那么今天我們就來看看Anroid中傳感器的使用&#xff0c;做一個類似于微信搖一搖的效果。 OK ,廢話不多說&#xff0c;我們就先來看看效果圖吧&#xff1a; 當我搖動手機的時候這里的動畫效果…

圖像

背景圖案的設置 將圖片插入到網頁中去 用圖像作為超鏈接 使用工具建立地圖索引 切片索引 為網站添加圖標 5.1 背景圖案的設置&#xff08;背景不占位置&#xff0c;不影響文本的輸入&#xff09; 格式&#xff1a;<body background"URL"> 5.2 將圖片插入…

Maven構建依賴項

熟悉發行版和快照依賴項的Maven和Gradle用戶可能不了解TeamCity快照依賴項&#xff0c;或者認為他們與Maven相關&#xff08;這是不正確的&#xff09;。 熟悉工件和快照依賴關系的TeamCity用戶可能不知道&#xff0c;除了TeamCity提供的插件之外&#xff0c;添加Artifactory插…

Java兩種設計模式_23種設計模式(11)java策略模式

23種設計模式第四篇&#xff1a;java策略模式定義&#xff1a;定義一組算法&#xff0c;將每個算法都封裝起來&#xff0c;并且使他們之間可以互換。類型&#xff1a;行為類模式類圖&#xff1a;策略模式是對算法的封裝&#xff0c;把一系列的算法分別封裝到對應的類中&#xf…

Problem E: 平面上的點——Point類 (II)

Description 在數學上&#xff0c;平面直角坐標系上的點用X軸和Y軸上的兩個坐標值唯一確定。現在我們封裝一個“Point類”來實現平面上的點的操作。 根據“append.cc”&#xff0c;完成Point類的構造方法和show()方法&#xff0c;輸出各Point對象的構造和析構次序。 接口描述&a…

MFC 控件RadioButton和CheckBox區別

1. 單個RadioButton在選中后&#xff0c;通過點擊無法變為未選中 單個CheckBox在選中后&#xff0c;通過點擊可以變為未選中 2. 一組RadioButton&#xff0c;只能同時選中一個 一組CheckBox&#xff0c;能同時選中多個 3. RadioButton在大部分UI框架中默認都以圓形表示 CheckBo…

什么是ActiveMQ?

盡管Active MQ網站已經對ActiveMQ進行了詳盡的介紹&#xff0c;但我想在其定義中添加更多上下文。 從ActiveMQ項目的網站上&#xff1a; “ ActiveMQ是JMS 1.1的開源實現&#xff0c;是J2EE 1.4規范的一部分。” 這是我的看法&#xff1a;ActiveMQ是一種開源消息傳遞軟件&…

字符串倒著輸出java_Java 輸出反轉字符串

Java 輸出反轉字符串public class Test {public static void main(String args[]){try{// 獲取鍵盤輸入的字符串BufferReader f new BufferReader(new inputStreamReader(System.in));String str f.readline();for (int i str.length() -1 ; i >0 ; i--) {System.out.p…

webpack基礎入門

我相信&#xff0c;有不少的朋友對webpack都有或多或少的了解。網上也有了各種各樣的文章&#xff0c;文章內作者也寫出了不少自己對于webpack這個工具的理解。在我剛剛接觸webpack的時候&#xff0c;老實說&#xff0c;網上大部分的文章我是看不懂的。。webpack里面有很多名詞…

位運算基礎

異或運算的基礎有點忘記了 先介紹一下。。2個數異或 就是對于每一個二進制位進行位運算 具有2個特殊的性質 1、一個數異或本身恒等于0&#xff0c;如5^5恒等于0&#xff1b; 2、一個數異或0恒等于本身&#xff0c;如5^0恒等于5。 3 滿足交換律 1.交換數字這個性質能利用與交換數…

JAXB自定義綁定– Java.util.Date / Spring 3序列化

JaxB可以處理Java.util.Date序列化&#xff0c;但是需要以下格式&#xff1a; “ yyyy-MM-ddTHH&#xff1a;mm&#xff1a;ss ”。 如果需要將日期對象格式化為另一種格式怎么辦&#xff1f; 我有同樣的問題時&#xff0c;我正在同春MVC 3和Jackson JSON處理器 &#xff0c;最…

雙足機器人簡單步態生成

讓機器人行走最簡單的方法是先得到一組步態曲線&#xff0c;即腿部每個關節隨時間運動的角度值。可以在ADAMS或3D Max、Blender等軟件中建立好機構/骨骼模型&#xff0c;設計出腳踝和髖關節的運動曲線&#xff0c;然后進行逆運動學解算&#xff0c;測量每個關節在運動過程中的轉…

重新訪問了訪客模式

訪客模式是面向對象設計中最被高估但又被低估的模式之一。 高估了它&#xff0c;因為它常常被選擇得太快&#xff08; 可能是由建筑宇航員選擇的 &#xff09;&#xff0c;然后以錯誤的方式添加時會膨脹本來非常簡單的設計。 如果您不遵循教科書示例&#xff0c;那么它可能會非…