using System; using System.Collections.Generic; using System.Linq; using global::System.Reflection; using global::Pilz.Reflection.PluginSystem.Attributes; namespace Pilz.Reflection.PluginSystem { public class Plugin { /// /// A collection of Methods that contains PluginFunctions that will be called automatically when loading the Plugin, as long as the property AutoCallMainFunctions is set to True. /// /// public IReadOnlyList MainFunctions { get; private set; } /// /// A collection of Methods with a FunctionCode (excluding all PluginFunctions from MainFunctions). /// /// public IReadOnlyList PluginFunctions { get; private set; } /// /// Gets the assembly that contains the PluginFunctions of this Plugin /// /// public Assembly Assembly { get; private set; } /// /// Gets the main module that contains the PluginFunctions of this Plugin /// /// public Type MainModule { get; private set; } /// /// Load a new Plugin and its PluginFunctions. /// /// /// If true, all MainMethods of a Plugin will be called as soon as a Plugin is loaded. /// The name of the type where to search for Methods when loading a new Plugin. public Plugin(string filePath, bool autoCallMainFunction, string entryTypeName) { Assembly = Assembly.LoadFile(filePath); MainModule = Assembly.GetType(entryTypeName); if (MainModule is null) { throw new PluginLoadException("Plugin Modul not found!"); } // Define the attribute types to observe var entryMethodType = typeof(LoadMethodAttribute); var implementMethodType = typeof(PluginFunctionAttribute); // Create the lists var mainMethods = new List(); var implementMethods = new List(); // Search for PluginFunctions foreach (MethodInfo mi in MainModule.GetMethods()) { bool found = false; // Check if the method has one of the defined attributes foreach (Attribute attr in Attribute.GetCustomAttributes(mi)) { if (!found) { var t = attr.GetType(); switch (t) { case var @case when @case == entryMethodType: { mainMethods.Add(new PluginFunction(mi, this)); break; } case var case1 when case1 == implementMethodType: { { var withBlock = (PluginFunctionAttribute)attr; implementMethods.Add(new PluginFunction(mi, this, withBlock.Params, withBlock.FunctionCode)); } break; } } found = true; } } } // Set the collections MainFunctions = mainMethods; PluginFunctions = implementMethods; // Call all PluginFunctions in MainFunctions if (autoCallMainFunction) { foreach (PluginFunction func in mainMethods) { var @params = func.Method.GetParameters(); if (@params.Length == 1) { string startupExe = Assembly.GetEntryAssembly().Location; var args = new[] { startupExe, filePath }; func.Invoke(new[] { args }); } else if (!@params.Any()) { func.Invoke(); } } } } /// /// Get all PluginFunctions that have one of the given function codes. /// /// /// public IEnumerable GetFunctions(params string[] funcCodes) { var funcs = new List(); foreach (PluginFunction func in PluginFunctions) { if (funcCodes.Contains(func.FunctionCode)) { funcs.Add(func); } } return funcs; } /// /// Get the first PluginFunction that have the one of the given function codes. /// /// public PluginFunction GetFunction(params string[] funcCodes) { PluginFunction f = null; foreach (PluginFunction func in PluginFunctions) { if (f is null && funcCodes.Contains(func.FunctionCode)) { f = func; } } return f; } } }