C#でプラグイン機能を実装しよう!

 

 

こんにちは。ナガオカ(@boot_kt)です。

 

C#でプラグイン機能を作る!!!

それだけだっ!!

 

ただ、それだけだと他のブログさんの記事と似たような内容になるので、僕なりにちょっとだけ工夫しています

 

CUI版とGUI版の2種類作ってます

CUI版は他の記事と同じような内容ですが、GUI版は実践的に使うならこういうことできると幸せになれるかな、と思ったことを実装しています

 

参考になれば嬉しいです

 

参考にしたURL
参考にさせて頂いた記事です
ぜひこちらもご覧ください

 

私にとっては、C#のプラグインの記事の中では、この記事が一番シンプルで分かりやすかったです。

 

その他の記事もとても参考になりました。

 

ありがとうございました。

この記事を読む前に、ぜひ上記の記事を先にご覧ください。

 

 

 

 

まずはC#でプラグインの概要

この記事を読まれる方ならプラグインはお分かりでしょうから、ソースコードの構成とか大雑把に説明します

 

以下の三つがあればプラグイン機能を試すことができます

  1. メインのプログラム
    • ファイル形式:EXE
    • プラグインのDLLが所定のフォルダにあれば、プラグインを読み込んでプラグインを実行します
      プラグインのDLLが所定のフォルダに無ければ何事もなく何もしません
    • この記事ではGUI版とCUI版の二種類を解説します
      CUIで解説されても、実践ではGUIでしょうから応用しづらいかと思い、GUI版も解説します
      と言っても、どっちも作り方は基本的には同じです
  2. プラグインのベース
  3. プラグイン
    • ファイル形式:DLL
    • プラグインベースを取り込んで継承して作ります

 

ソースコードを見た方が早い!

ソースコード貼り付けておきます

コメント書いてるので、それを読んでください

 

解説はしません

書くのが面倒ってのもありますが(笑)、ソースコードとコメントだけ見れば充分理解できると思います

 

プロジェクト一式はGitHubに置いてます

ダウンロードしてもらって、Visual Studio 2017とかで参照設定し直してビルドすれば使えるでしょう

GitHubはこちら >> PluginSample_AbstractClassVersion | GitHub

 

MainProgramCUIプロジェクト

using System;

namespace MainProgramCUI
{
	class Program
	{
		static void Main(string[] args)
		{
			// プラグインをロードして実行
			var plugin = new PluginAccessor();
			var numDll = plugin.LoadPlugins();
			Console.WriteLine($"[Main] numDll={numDll}");
			Console.WriteLine("");


			Console.WriteLine("[Main] 全てのプラグイン実行=========");
			plugin.AllPluginExec();
			Console.WriteLine("");


			Console.WriteLine("[Main] 1つ目のプラグイン実行=========");
			var idxDll = 0;
			plugin.PluginShow(idxDll);
			plugin.PluginSetNo(idxDll, 5);
			var getno = plugin.PluginGetNo(idxDll);
			Console.WriteLine($"[Main] getno1={getno}");
			Console.WriteLine("");


			Console.WriteLine("[Main] 2つ目のプラグイン実行=========");
			idxDll = 1;
			plugin.PluginShow(idxDll);
			plugin.PluginSetNo(idxDll, 7);
			getno = plugin.PluginGetNo(idxDll);
			Console.WriteLine($"[Main] getno2={getno}");
			Console.WriteLine("");


			// 処理結果を見るために、コンソール画面が落ちないように一時停止
			Console.ReadLine();
		}
	}
}

 

using PluginBaseDLL;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

// 参照の追加:PluginBaseDLL.dll
// このEXEと同じ階層のPluginフォルダにPluginSample1.dllとPluginSample2.dllを入れておく

namespace MainProgramCUI
{
	public class PluginAccessor
	{
		// 今回のサンプルではこのリストにPluginSample1.dllとPluginSample2.dllが登録される
		List _listPluginClass = new List();

		/// 
		/// プラグインフォルダに入ってるプラグイン(DLL)を読み取る
		/// 
		/// ロードできたDLLの個数
		public int LoadPlugins()
		{
			//---------------------------------------------------------------------------------
			// プラグインDLLの格納されたフォルダをEXEと同じ階層にあるPluginsフォルダとする
			//---------------------------------------------------------------------------------
			string strPluginFolder = Environment.CurrentDirectory + "\\Plugins";

			//---------------------------------------------------------------------------------
			// プラグインフォルダ内のDLLファイルを取得
			//---------------------------------------------------------------------------------
			// 今回のサンプルではPluginSample1.dllとPluginSample2.dllと取得できるはず
			string[] aryDllFilePath = Directory.GetFiles(strPluginFolder, "*.dll");

			//---------------------------------------------------------------------------------
			// PluginBaseClassの派生クラスのインスタンスを作成し、aryPluginBaseに追加
			//---------------------------------------------------------------------------------
			foreach (var sDLLFilePath in aryDllFilePath)
			{
				//---------------------------------------------------------------------------------
				// アセンブリをロード
				//---------------------------------------------------------------------------------
				var assembly = Assembly.LoadFile(sDLLFilePath);
				if (assembly == null)
				{
					continue;
				}
				//---------------------------------------------------------------------------------
				// アセンブリ内の型定義を取得
				//---------------------------------------------------------------------------------
				Type[] types = assembly.GetTypes();
				//---------------------------------------------------------------------------------
				// PluginInterfaceまたはPluginBaseClassを継承するクラスをデフォルト
				// コンストラクタ経由でインスタンスを作成→各配列に追加する
				//---------------------------------------------------------------------------------
				foreach (var type in types)
				{
					//-----------------------------------------------------------------------------
					// クラス以外の型、抽象クラス、非公開クラス、外部利用不可なクラスは除く
					//-----------------------------------------------------------------------------
					if (!type.IsClass || type.IsAbstract || type.IsNotPublic || !type.IsVisible)
					{
						continue;
					}
					//-----------------------------------------------------------------------------
					// ベースクラスPluginBaseClassを継承していることを確認
					//-----------------------------------------------------------------------------
					if (type.IsSubclassOf(typeof(PluginBaseClass)))
					{
						// (公開)デフォルトコンストラクタを取得
						var ci = type.GetConstructor(Type.EmptyTypes);
						if (ci == null)
						{
							// デフォルトコンストラクタが無いだとっ!?
							continue;
						}
						// インスタンス作成
						// カンケー無いけど、Invokeってのは呼び出すっていう意味
						var instance = ci.Invoke(new object[] { });
						if (instance == null)
						{
							// インスタンスを作成出来無いだとっ!?
							continue;
						}

						// チェックを無事通ったものだけがリストに登録される
						_listPluginClass.Add((PluginBaseClass)instance);
					}
				}
			}

			//-----------------------------------------------------------------------------
			// CUIで動くことを指定
			//-----------------------------------------------------------------------------
			foreach (var plugin in _listPluginClass)
			{
				plugin.action_mode = PluginBaseClass.ACTION_MODE.CUI;
			}

			//-----------------------------------------------------------------------------
			// ロードできたDLLの個数を返す
			//-----------------------------------------------------------------------------
			return _listPluginClass.Count;
		}

		/// 
		/// 全てのプラグインを実行する
		/// ※先にLoadPlugins()でプラグインを読み込んでいること
		/// 
		public void AllPluginExec()
		{
			foreach (var plugin in _listPluginClass)
			{
				plugin.Show();
				plugin.SetNo(3);
				var ret = plugin.GetNo();
				Console.WriteLine($"[PluginAccessor] ret={ret}");
				Console.WriteLine("-------------");
			}
		}

		/// 
		/// 個別にプラグインのShow()メソッドを実行
		/// ※先にLoadPlugins()でプラグインを読み込んでいること
		/// ※本来なら引数のidxDllのチェックが必要だが省略
		/// 
		/// 
		public void PluginShow(int idxDll)
		{
			_listPluginClass[idxDll].Show();
		}
		/// 
		/// 個別にプラグインのSetNo()メソッドを実行
		/// ※先にLoadPlugins()でプラグインを読み込んでいること
		/// ※本来なら引数のidxDllのチェックが必要だが省略
		/// 
		/// 
		/// 
		public void PluginSetNo(int idxDll, int no)
		{
			_listPluginClass[idxDll].SetNo(no);
		}
		/// 
		/// 個別にプラグインのGetNo()メソッドを実行
		/// ※先にLoadPlugins()でプラグインを読み込んでいること
		/// ※本来なら引数のidxDllのチェックが必要だが省略
		/// 
		/// 
		/// 
		public int PluginGetNo(int idxDll)
		{
			return _listPluginClass[idxDll].GetNo();
		}
	}
}

 

MainProgramGUI

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MainProgramGUI
{
	static class Program
	{
		/// 
		/// アプリケーションのメイン エントリ ポイントです。
		/// 
		[STAThread]
		static void Main()
		{
			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);
			Application.Run(new MainForm());
		}
	}
}

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static PluginBaseDLL.PluginBaseClass;

namespace MainProgramGUI
{
	public partial class MainForm : Form
	{
		///// 
		///// ログレベル
		///// 
		//public enum LOG_LEVEL
		//{
		//    TRACE,
		//    DEBUG,
		//    INFO,
		//    WARN,
		//    ERROR,
		//    FATAL,
		//}

		/// 
		/// フォームのコンストラクタ
		/// 
		public MainForm()
		{
			InitializeComponent();
		}

		/// 
		/// 画面部品のリストボックスにログ出力
		/// 
		/// 
		/// 
		private void LogOut(LOG_LEVEL level, string log)
		{
			listLog.Items.Add($"{DateTime.Now} [{level.ToString()}] {log}");
			listLog.SelectedIndex = listLog.Items.Count - 1;
		}





		#region イベントハンドラ
		/// 
		/// Thread Startボタンのクリックイベント
		/// 
		/// 
		/// 
		private void btnThreadStart_Click(object sender, EventArgs e)
		{
			cancelTokenSource = new CancellationTokenSource();
			cancelToken = cancelTokenSource.Token;

			var task = new Task(() => ThreadWorkerAsync());
			task.Start();

			// ↑じゃなくて、↓のawaitならスレッドがメインのままなのでInvoke()なんか使わなくてもいいはず
			//await ThreadWorkerAsync();
			// ↑await使うならbtnThreadStart_Click()をasyncにする

			listLog.Items.Add("-------------");
		}
		/// 
		/// Thread Stopボタンのクリックイベント
		/// 
		/// 
		/// 
		private void btnThreadStop_Click(object sender, EventArgs e)
		{
			cancelTokenSource.Cancel();
		}
		#endregion


		#region UIスレッドとワーカースレッドのI/F
		/// 
		/// ワーカースレッドからUIスレッドの画面部品のリストボックスにログを出力するためのデリゲート
		/// 
		/// 
		/// 
		delegate void LogOutDelegate(LOG_LEVEL level, string log);
		/// 
		/// ワーカースレッドからUIスレッドの画面部品のリストボックスにログを出力
		/// 
		/// 
		/// 
		public void LogOutInvoke(LOG_LEVEL level, string log)
		{
			// カンケー無いけど、Invokeってのは呼び出すっていう意味
			Invoke(new LogOutDelegate(LogOut), level, log);
		}
		#endregion


		#region ワーカースレッド
		// ワーカースレッドのキャンセル
		CancellationTokenSource cancelTokenSource;
		CancellationToken cancelToken;

		/// 
		/// ワーカースレッド本体
		/// 
		/// 
		private async Task ThreadWorkerAsync()
		{
			// プラグインをロードして実行
			var plugin = new PluginAccessor();
			var numDll = plugin.LoadPlugins();
			LogOutInvoke(LOG_LEVEL.INFO, $"[Main] numDll={numDll}");
			LogOutInvoke(LOG_LEVEL.INFO, "");



			while (!cancelToken.IsCancellationRequested)
			{

				LogOutInvoke(LOG_LEVEL.INFO, "[Main] 全てのプラグイン実行=========");
				plugin.AllPluginExec(new PluginLogWriter(this));
				LogOutInvoke(LOG_LEVEL.INFO, "");


				LogOutInvoke(LOG_LEVEL.INFO, "[Main] 1つ目のプラグイン実行=========");
				var idxDll = 0;
				plugin.PluginShow(idxDll);
				plugin.PluginSetNo(idxDll, 5);
				var getno = plugin.PluginGetNo(idxDll);
				LogOutInvoke(LOG_LEVEL.INFO, $"[Main] getno1={getno}");
				LogOutInvoke(LOG_LEVEL.INFO, "");


				LogOutInvoke(LOG_LEVEL.INFO, "[Main] 2つ目のプラグイン実行=========");
				idxDll = 1;
				plugin.PluginShow(idxDll);
				plugin.PluginSetNo(idxDll, 7);
				getno = plugin.PluginGetNo(idxDll);
				LogOutInvoke(LOG_LEVEL.INFO, $"[Main] getno2={getno}");
				LogOutInvoke(LOG_LEVEL.INFO, "");

				// ワーカースレッドから画面部品にはアクセスできない
				// 画面部品にアクセスできるのはUIスレッドのみ
				// なので、↓の二行は例外になる
				// listLog.Items.Add($"{DateTime.Now} [{LOG_LEVEL.ERROR}] ワーカースレッド");
				// LogOut(LOG_LEVEL.INFO, "ワーカースレッド");

				// ワーカースレッドから画面部品にアクセスするにはInvoke()を使う
				// ↓
				LogOutInvoke(LOG_LEVEL.INFO, "ワーカースレッド実行中");
				LogOutInvoke(LOG_LEVEL.INFO, "");
				LogOutInvoke(LOG_LEVEL.INFO, "");

				await Task.Delay(3000);
			}
			LogOutInvoke(LOG_LEVEL.INFO, "ワーカースレッド終了");
		}
		#endregion
	}
}

 

using PluginBaseDLL;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

// 参照の追加:PluginBaseDLL.dll
// このEXEと同じ階層のPluginフォルダにPluginSample1.dllとPluginSample2.dllを入れておく


namespace MainProgramGUI
{
	public class PluginAccessor
	{
		// 今回のサンプルではこのリストにPluginSample1.dllとPluginSample2.dllが登録される
		List _listPluginClass = new List();

		/// 
		/// プラグインフォルダに入ってるプラグイン(DLL)を読み取る
		/// 
		/// ロードできたDLLの個数
		public int LoadPlugins()
		{
			//---------------------------------------------------------------------------------
			// プラグインDLLの格納されたフォルダをEXEと同じ階層にあるPluginsフォルダとする
			//---------------------------------------------------------------------------------
			string strPluginFolder = Environment.CurrentDirectory + "\\Plugins";

			//---------------------------------------------------------------------------------
			// プラグインフォルダ内のDLLファイルを取得
			//---------------------------------------------------------------------------------
			// 今回のサンプルではPluginSample1.dllとPluginSample2.dllと取得できるはず
			string[] aryDllFilePath = Directory.GetFiles(strPluginFolder, "*.dll");

			//---------------------------------------------------------------------------------
			// PluginBaseClassの派生クラスのインスタンスを作成し、aryPluginBaseに追加
			//---------------------------------------------------------------------------------
			foreach (var sDLLFilePath in aryDllFilePath)
			{
				//---------------------------------------------------------------------------------
				// アセンブリをロード
				//---------------------------------------------------------------------------------
				var assembly = Assembly.LoadFile(sDLLFilePath);
				if (assembly == null)
				{
					continue;
				}
				//---------------------------------------------------------------------------------
				// アセンブリ内の型定義を取得
				//---------------------------------------------------------------------------------
				Type[] types = assembly.GetTypes();
				//---------------------------------------------------------------------------------
				// PluginInterfaceまたはPluginBaseClassを継承するクラスをデフォルト
				// コンストラクタ経由でインスタンスを作成→各配列に追加する
				//---------------------------------------------------------------------------------
				foreach (var type in types)
				{
					//-----------------------------------------------------------------------------
					// クラス以外の型、抽象クラス、非公開クラス、外部利用不可なクラスは除く
					//-----------------------------------------------------------------------------
					if (!type.IsClass || type.IsAbstract || type.IsNotPublic || !type.IsVisible)
					{
						continue;
					}
					//-----------------------------------------------------------------------------
					// ベースクラスPluginBaseClassを継承していることを確認
					//-----------------------------------------------------------------------------
					if (type.IsSubclassOf(typeof(PluginBaseClass)))
					{
						// (公開)デフォルトコンストラクタを取得
						var ci = type.GetConstructor(Type.EmptyTypes);
						if (ci == null)
						{
							// デフォルトコンストラクタが無いだとっ!?
							continue;
						}
						// インスタンス作成
						// カンケー無いけど、Invokeってのは呼び出すっていう意味
						var instance = ci.Invoke(new object[] { });
						if (instance == null)
						{
							// インスタンスを作成出来無いだとっ!?
							continue;
						}

						// チェックを無事通ったものだけがリストに登録される
						_listPluginClass.Add((PluginBaseClass)instance);
					}
				}
			}

			//-----------------------------------------------------------------------------
			// GUIで動くことを指定
			//-----------------------------------------------------------------------------
			foreach (var plugin in _listPluginClass)
			{
				plugin.action_mode = PluginBaseClass.ACTION_MODE.GUI;
			}

			//-----------------------------------------------------------------------------
			// ロードできたDLLの個数を返す
			//-----------------------------------------------------------------------------
			return _listPluginClass.Count;
		}

		/// 
		/// 全てのプラグインを実行する
		/// ※先にLoadPlugins()でプラグインを読み込んでいること
		/// 
		public void AllPluginExec(TextWriter newOut)
		{
			foreach (var plugin in _listPluginClass)
			{
				plugin.SetOut(newOut);
				plugin.Show();
				plugin.SetNo(3);
				var ret = plugin.GetNo();
				Console.WriteLine($"[PluginAccessor] ret={ret}");
				Console.WriteLine("-------------");
			}
		}

		/// 
		/// 個別にプラグインのShow()メソッドを実行
		/// ※先にLoadPlugins()でプラグインを読み込んでいること
		/// ※本来なら引数のidxDllのチェックが必要だが省略
		/// 
		/// 
		public void PluginShow(int idxDll)
		{
			_listPluginClass[idxDll].Show();
		}
		/// 
		/// 個別にプラグインのSetNo()メソッドを実行
		/// ※先にLoadPlugins()でプラグインを読み込んでいること
		/// ※本来なら引数のidxDllのチェックが必要だが省略
		/// 
		/// 
		/// 
		public void PluginSetNo(int idxDll, int no)
		{
			_listPluginClass[idxDll].SetNo(no);
		}
		/// 
		/// 個別にプラグインのGetNo()メソッドを実行
		/// ※先にLoadPlugins()でプラグインを読み込んでいること
		/// ※本来なら引数のidxDllのチェックが必要だが省略
		/// 
		/// 
		/// 
		public int PluginGetNo(int idxDll)
		{
			return _listPluginClass[idxDll].GetNo();
		}
	}
}

 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static MainProgramGUI.MainForm;
using static PluginBaseDLL.PluginBaseClass;

namespace MainProgramGUI
{
	public class PluginLogWriter : TextWriter
	{
		public override Encoding Encoding => Encoding.UTF8;

		MainForm _frm = null;

		/// 
		/// コンストラクタ
		/// 
		/// 呼び元のForm
		public PluginLogWriter(MainForm frm)
		{
			this._frm = frm;
		}

		/// 
		/// 
		/// 
		/// 
		public override void WriteLine(string value)
		{
			_frm.LogOutInvoke(LOG_LEVEL.ERROR, value);
		}

		public override void WriteLine(string format, object arg0)
		{
			LOG_LEVEL level = (LOG_LEVEL)arg0;
			_frm.LogOutInvoke(level, format);
		}

	}
}

 

PluginBaseDLL

using System;
using System.IO;

namespace PluginBaseDLL
{
	/// 
	/// プラグインベースのクラス
	/// 
	public abstract class PluginBaseClass
	{
		/// 
		/// 動作モード
		/// GUIで動くのか、CUIで動くのか
		/// 
		public enum ACTION_MODE
		{
			CUI,
			GUI,
		}
		public ACTION_MODE action_mode { get; set; } = ACTION_MODE.CUI;



		/// 
		/// ログレベル
		/// MainProgramGUIのLOG_LEVELと同じもの
		/// 本当は一元管理にして、MainProgramGUIとPluginBaseで共通的に参照するのがいいのだろうけど
		/// そこまでするのは面倒なのでMainProgramGUIからコピるだけにしておく
		/// 
		public enum LOG_LEVEL
		{
			TRACE,
			DEBUG,
			INFO,
			WARN,
			ERROR,
			FATAL,
		}


		/// 
		/// 表示メソッド
		/// 
		public abstract void Show();

		/// 
		/// 数値をセット
		/// 
		/// 
		public abstract void SetNo(int no);

		/// 
		/// 数値をゲット
		/// 
		/// 
		public abstract int GetNo();

		/// 
		/// 標準出力先を変更
		/// 
		/// 呼び側で自作のTextWriter系クラスを使ってログ出力する
		/// 今回のサンプルでは、画面部品のログ用リストボックスに出力することになる
		/// 子クラスでこれを触る必要は無い
		/// オーバーライド禁止
		/// 
		/// 子クラスでConsole.WriteLine(LOG_LEVEL.INFO, "ログの文言だよ~ん");って感じで書いてもらえば
		/// 呼び側で自作のTextWriter系クラスへ渡すことができる
		/// 
		/// 
		public void SetOut(TextWriter newOut)
		{
			Console.SetOut(newOut);
		}

	}
}

 

PluginSample1

using PluginBaseDLL;
using System;

// 参照の追加:PluginBaseDLL.dll
// GUIモードの時のLOG_LEVELの設定値は適当なので意味はない、呼び出し側でそのレベルが取れていることを確認したいだけ


namespace PluginSample1
{
	public class PluginSampleClass1 : PluginBaseClass
	{
		private int _no;

		/// 
		/// 表示メソッド
		/// 
		public override void Show()
		{
			if (action_mode == ACTION_MODE.GUI)
			{
				// GUIモード
				Console.WriteLine("プラグインサンプル1のShowメソッドG", LOG_LEVEL.WARN);
			}
			else
			{
				// GUIモード以外(CUIモードと、無いと思うけど予期しないモード)
				Console.WriteLine("プラグインサンプル1のShowメソッドC");
			}
		}

		/// 
		/// 数値をセット
		/// 
		/// 
		public override void SetNo(int no)
		{
			//---------------------------------------------------------------------------------
			// 単にログを出したいだけ
			//---------------------------------------------------------------------------------
			if (action_mode == ACTION_MODE.GUI)
			{
				// GUIモード
				Console.WriteLine($"プラグインサンプル1のSetNoメソッドG:no={no}", LOG_LEVEL.FATAL);
			}
			else
			{
				// GUIモード以外(CUIモードと、無いと思うけど予期しないモード)
				Console.WriteLine($"プラグインサンプル1のSetNoメソッドC:no={no}");
			}

			//---------------------------------------------------------------------------------
			// このメソッドでやりたいこと
			//---------------------------------------------------------------------------------
			_no = no;
		}

		/// 
		/// 数値をゲット
		/// 
		/// 
		public override int GetNo()
		{
			//---------------------------------------------------------------------------------
			// 単にログを出したいだけ
			//---------------------------------------------------------------------------------
			if (action_mode == ACTION_MODE.GUI)
			{
				// GUIモード
				Console.WriteLine($"プラグインサンプル1のGetNoメソッドG:no={_no}", LOG_LEVEL.ERROR);
			}
			else
			{
				// GUIモード以外(CUIモードと、無いと思うけど予期しないモード)
				Console.WriteLine($"プラグインサンプル1のGetNoメソッドC:no={_no}");
			}

			//---------------------------------------------------------------------------------
			// このメソッドでやりたいこと
			//---------------------------------------------------------------------------------
			return _no + 10;
		}
	}
}

 

PluginSample2

using PluginBaseDLL;
using System;

// 参照の追加:PluginBaseDLL.dll
// GUIモードの時のLOG_LEVELの設定値は適当なので意味はない、呼び出し側でそのレベルが取れていることを確認したいだけ

namespace PluginSample2
{
	public class PluginSampleClass2 : PluginBaseClass
	{
		private int _no;

		/// 
		/// 表示メソッド
		/// 
		public override void Show()
		{
			if (action_mode == ACTION_MODE.GUI)
			{
				// GUIモード
				Console.WriteLine("プラグインサンプル2のShowメソッドG", LOG_LEVEL.TRACE);
			}
			else
			{
				// GUIモード以外(CUIモードと、無いと思うけど予期しないモード)
				Console.WriteLine("プラグインサンプル2のShowメソッドC");
			}
		}

		/// 
		/// 数値をセット
		/// 
		/// 
		public override void SetNo(int no)
		{
			//---------------------------------------------------------------------------------
			// 単にログを出したいだけ
			//---------------------------------------------------------------------------------
			if (action_mode == ACTION_MODE.GUI)
			{
				// GUIモード
				Console.WriteLine($"プラグインサンプル2のSetNoメソッドG:no={no}", LOG_LEVEL.WARN);
			}
			else
			{
				// GUIモード以外(CUIモードと、無いと思うけど予期しないモード)
				Console.WriteLine($"プラグインサンプル2のSetNoメソッドC:no={no}");
			}

			//---------------------------------------------------------------------------------
			// このメソッドでやりたいこと
			//---------------------------------------------------------------------------------
			_no = no;
		}

		/// 
		/// 数値をゲット
		/// 
		/// 
		public override int GetNo()
		{
			//---------------------------------------------------------------------------------
			// 単にログを出したいだけ
			//---------------------------------------------------------------------------------
			if (action_mode == ACTION_MODE.GUI)
			{
				// GUIモード
				Console.WriteLine($"プラグインサンプル2のGetNoメソッドG:_no={_no}", LOG_LEVEL.DEBUG);
			}
			else
			{
				// GUIモード以外(CUIモードと、無いと思うけど予期しないモード)
				Console.WriteLine($"プラグインサンプル2のGetNoメソッドC:_no={_no}");
			}

			//---------------------------------------------------------------------------------
			// このメソッドでやりたいこと
			//---------------------------------------------------------------------------------
			return _no + 20;
		}
	}
}

 

 

広告




 

さいごに、

プラグイン機能を実装することあるのかな?とは思うんだけど、後からの対応は難しいだろうから、最初にデザインしておかないといけませんね
でもまぁ、プラグイン機能があるとなんかカッコイイよね!(笑)

他の言語でのプラグイン機能の作り方ってよく知らないんだけど、C#の場合は結構簡単ですね
DLLを動的に読み込んでリフレクション使ってるだけだし、メソッドの呼び方も普通だし、「挑戦」というほど難しくないけど挑戦してみてはどうでしょうか

 

参考書籍

 


 

プログラミング のレッスンに興味がある方、レッスン内容を聞いてみたい方、なんなりとお問い合わせください。
無料体験レッスンもありますのでお気軽にどうぞ!!!

 

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

ABOUTこの記事をかいた人

Windows/Mac/Linuxを使う現役システムエンジニア&プログラマ。オープン系・組み込み系・制御系・Webシステム系と幅広い案件に携わる。C言語やC#やJava等数多くのコンパイラ言語を経験したが、少し飽きてきたので、最近はRubyやPython、WordPressなどのWeb系を修得中。初心者向けのプログラミング教室も運営中。オンライン・対面・出張等でプログラミングをレッスンします。