c# 插件式程序示例

插件的好处不用多说,只要接口一样,可以任意更换表现形式。

步骤如下:

1. 新建一个类库工程MyPlug。

  默认创建Class1.cs文件,此类用于继承接口,并处理接口方法。

  a. 在该工程中新建类Iplugin,并定义接口,代码如下:

namespace MyPlug
{
    public interface Iplugin
    {
        void OnShowDlg(int No);//No表示要显示几号窗口
        string OnShowInfo();
    }
}

  b.在该工程中新建两个窗体,Form1,Form2。界面如下

     Form1                                                Form2

      

  c. 在刚才的Class1.cs中继承上述接口,并实现方法

namespace MyPlug
{
    public class Class1 : Iplugin
    {
        public void OnShowDlg(int No)
        {
            Form form;
            switch(No)    
            {
                case 2:
                    form = new Form2();
                    break;
                default:
                    form = new Form1();            
                    break;
            }
            form.ShowDialog();
        }
        public string OnShowInfo()
        {
            return "sylf-form:My";
        }
    }
}

  d. 生成解决方案,获得动态链接库dll。后续会修改dll的输出路径


2. 在该解决方案中新建一个form窗体工程plugDemo

  a.新建一个类 PluginLoader,专门处理动态链接库的加载和反射获取dll的实例:

(记得把刚才类库的输出路径改成现在这个窗体工程的Debug的plugin目录,方法就是右键上述类库的工程,选择属性,在生成选项卡的输出部分选择输出路径为这个窗体工程的Debug的plugin目录,就可以了。

或者把上述类库生成的dll手动拷贝到这个窗体工程的Debug的plugin目录,也是可以的。)

namespace plugDemo
{
    public static class PluginLoader
    {
        public static ArrayList plugins = new ArrayList();

        /// <summary>
        /// 判断DLL中是否继承了Iplugin接口
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        private static bool IsValidPlugin(Type t)
        {
            bool ret = false;
            Type[] interfaces = t.GetInterfaces();
            foreach (Type item in interfaces)
            {
                if (item.FullName.IndexOf( "Iplugin")>=0)
                {
                    ret = true;
                    break;
                }
            }
            return ret;
        }

        /// <summary>
        /// 加载插件,这里是在程序的Debug的plugin目录中搜索插件
        /// </summary>
        public static void LoadAllPlugins()
        {
            string[] files = Directory.GetFiles(Application.StartupPath + "\\plugin\\");
            foreach (string file in files)
            {
                string ext = file.Substring(file.LastIndexOf("."));
                if (ext != ".dll")
                    continue;
                try
                {
                    //加载插件的动态链接库
                    Assembly tmp = Assembly.LoadFile(file);
                    Type[] types = tmp.GetTypes();
                    foreach (Type t in types)
                    {
                        if (IsValidPlugin(t))//这两个if的功能是一样的
                        //if (t.GetInterface("Iplugin") != null)//判断该dll是否继承了Iplugin接口
                        {// 通过反射实例化
                            plugins.Add(tmp.CreateInstance(t.FullName));
                        }
                    }
                }
                catch (Exception err)
                {                    
                    throw err;
                }
            }
        }
    }
}

  b. 定义该工程的窗口界面如下:

  c. 响应按钮“载入插件”点击事件

namespace plugDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            textBox_FormNo.Text = "1";
            label_Error.Text = "";
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (Convert.ToInt32(textBox_FormNo.Text)>2 && Convert.ToInt32(textBox_FormNo.Text)<1)
            {
                label_Error.Text = "输入的窗口号不正确,强制为1号窗口";
                textBox_FormNo.Text = "1";
            }
            PluginLoader.LoadAllPlugins();
            if (PluginLoader.plugins.Count>0)
            {
                object obj = PluginLoader.plugins[0];
                Type t = obj.GetType();<span style="color:#cc33cc;">
                MethodInfo OnShowDlg = t.GetMethod("OnShowDlg");<span style="color:#000000;">//获取dll中的方法名</span></span><span style="color:#cc33cc;">
                OnShowDlg.Invoke(obj, new object[] { Convert.ToInt32(textBox_FormNo.Text) });</span>
            }
        }

    }
}

  d. 至此,生成解决方案就可以运行了。


3. 说明
   OnShowDlg如果没有参数,就是OnShowDlg.Invoke(obj,null);

                      如果有参数记得要传参数。如上面的示例,参数是int,换成Invoke的表达方式就好了。
           



  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
接口在C#中有广泛的使用场景,以下是一些常见的示例: 1. 定义插件系统:接口可以用于定义插件的规范,插件开发者只需实现接口中定义的方法,即可实现自己的功能,并与主程序进行交互。 2. 多态性和抽象:通过接口,可以实现多态性和抽象,使得代码更加灵活和可扩展。例如,定义一个形状的接口,然后让各种不同的形状类实现该接口,可以方便地对这些形状进行统一的处理。 3. 数据库操作:在数据库操作中,接口可以用于定义数据访问层的规范,不同的数据库操作类可以实现同一个接口,从而实现对不同数据库的统一操作。 以下是一个使用场景示例: ``` interface ILogger { void Log(string message); } class ConsoleLogger : ILogger { public void Log(string message) { Console.WriteLine(message); } } class FileLogger : ILogger { public void Log(string message) { // 将日志信息写入文件 } } class DatabaseService { private ILogger logger; public DatabaseService(ILogger logger) { this.logger = logger; } public void InsertData() { // 插入数据的逻辑 logger.Log("数据插入成功"); } } ``` 在上面的示例中,定义了一个 ILogger 接口,以及两个实现类 ConsoleLogger 和 FileLogger。DatabaseService 类依赖于 ILogger 接口,通过构造函数注入具体的日志记录器实例。在 InsertData 方法中,插入数据成功后会调用 ILogger 接口的 Log 方法,根据具体的实现类来记录日志。 通过接口的使用,可以方便地替换不同的日志记录器,实现了解耦和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值