在运行时轻松替换 dll

Replacing dll at runtime without pain

我有一个基本的 WinForm 解决方案(MS VS2013,.Net framework 4.5),用于使用反射测试 Dll 中包含的一些方法。我的目标是测试主应用程序它可以 运行 Dll 的两个方法(不引用项目中的 dll),然后 运行 四个方法(添加了 2 个方法)而不停止主应用程序和 运行 再次使用反射。

Reflections 工作正常(如果我停止主应用程序,替换 dll 文件并再次 运行 主应用程序,一切正常),但我无法替换 运行 处的 dll时间.

主应用有一个Timer控件,间隔为60秒。每 60 秒,执行一个方法来检查 DLL 文件是否在文件夹中。如果该文件夹中存在 DLL 文件,我想在主应用程序 (运行ning) 中使用新的 DLL,因为新的 DLL 包含旧方法(第一个 DLL)和主应用程序需要的其他方法。 但是,我收到文件正在使用中的错误消息。

我已经阅读了几个 post 问题、答案、MEF 文档、AppDomains 相关内容,但我无法将信息串联起来以实施解决方案。

其实我在post这个问题之前想了很多,但我承认我更愿意花一瞬间的羞耻感,知道你可以帮我一把。

如果您能帮助我提供代码和具体说明,那将对我有很大的帮助。

这是代码:

主要应用:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Reflection;
using System.IO;

namespace testDLLs
{
    public partial class Principal : Form
    {
        public Principal()
        {
            InitializeComponent();
        }

        private void Principal_Load(object sender, EventArgs e)
        {

            labelVersionDll.Text = metodosApoyo.RunDLLFunction("VersionOperaciones");

            string cListaOperaciones = metodosApoyo.RunDLLFunction("ListaOperaciones");

            string[] aOperaciones = cListaOperaciones.Split('|');

            comboBoxOperaciones.Items.Clear();

            foreach (string cOperacion in aOperaciones)
            {
                comboBoxOperaciones.Items.Add(cOperacion);
            }

            timerForUpdate.Interval = 60000;
            timerForUpdate.Enabled = true;


        }

        private void buttonRun_Click(object sender, EventArgs e)
        {
            int iOperador1, iOperador2;
            string resultadoDesdeDll = null;
            string cOperacionSeleccionada;

            Int32.TryParse(textBoxOperador1.Text, out iOperador1);
            Int32.TryParse(textBoxOperador2.Text, out iOperador2);

            cOperacionSeleccionada = comboBoxOperaciones.GetItemText(comboBoxOperaciones.SelectedItem);

            object[] parametersArray = new object[] { iOperador1, iOperador2 };

            resultadoDesdeDll = metodosApoyo.RunDLLFunction(cOperacionSeleccionada, parametersArray);

            textBoxResultado.Text = resultadoDesdeDll;
        }

        private void timerForUpdate_Tick(object sender, EventArgs e)
        {
            labelUpdateStatus.Text = "Checking updates ...";
            notifyIconUpdate.Visible = true;
            notifyIconUpdate.BalloonTipText = "Instalando nuevo DLL....";
            notifyIconUpdate.BalloonTipTitle = "Info:";

            notifyIconUpdate.ShowBalloonTip(5000);

            if (File.Exists(@"C:\DLLsForCopy\OperacionesDLL.dll"))
            {

                File.Copy(@"C:\DLLsForCopy\OperacionesDLL.dll", @"D:\DLLs\OperacionesDLL.dll", true);

                labelVersionDll.Text = metodosApoyo.RunDLLFunction("VersionOperaciones");
                string cListaOperaciones = metodosApoyo.RunDLLFunction("ListaOperaciones");
                string[] aOperaciones = cListaOperaciones.Split('|');
                comboBoxOperaciones.Items.Clear();
                foreach (string cOperacion in aOperaciones)
                {
                    comboBoxOperaciones.Items.Add(cOperacion);
                }
            }
            labelUpdateStatus.Text = "";
            notifyIconUpdate.Visible = false;
        }
    }
}

Class 在项目中,对于主要应用程序的某些功能:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace testDLLs
{
    class metodosApoyo
    {
        public static string RunDLLFunction(string cMetodo, object[] aParametros = null)
        {
            string cRetornoGlobal = "";

            Object resultado = null;

            string cOperacionSeleccionada = cMetodo;

            Assembly assembly = Assembly.LoadFile(@"D:\DLLs\OperacionesDLL.dll");
            Type type = assembly.GetType("OperacionesDLL.Operaciones");

            MethodInfo methodInfo = type.GetMethod(cOperacionSeleccionada);

            ParameterInfo[] parameters = methodInfo.GetParameters();
            object classInstance = Activator.CreateInstance(type, null);

            object[] parametersArray = null;

            if (aParametros != null)
            {
                parametersArray = new object[aParametros.Length];
                int i = 0;

                foreach (object value in aParametros)
                {
                    parametersArray[i] = aParametros[i];
                    i++;
                }
            }

            resultado = methodInfo.Invoke(methodInfo, parametersArray);

            cRetornoGlobal = (string)resultado;

            return cRetornoGlobal;
        }

    }
}

DLL 源 (OperacionesDLL.dll):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OperacionesDLL
{
    public class Operaciones
    {
        public static string VersionOperaciones()
        {
            string retorno;
            retorno = "1.0701-16";
            return retorno;
        }
        public static string ListaOperaciones()
        {
            string retorno;
            retorno = "Suma|Resta|Multiplicación|División";
            return retorno;
        }

        public static string Suma(int operador1, int operador2)
        {
            int resultado;
            string retorno;
            resultado = operador1 + operador2;
            retorno = resultado.ToString();
            return retorno;
        }

        public static string Resta(int operador1, int operador2)
        {
            int resultado;
            string retorno;
            resultado = operador1 - operador2;
            retorno = resultado.ToString();
            return retorno;
        }

        public static string Multiplicación(int operador1, int operador2)
        {
            int resultado;
            string retorno;
            resultado = operador1 * operador2;
            retorno = resultado.ToString();
            return retorno;
        }

        public static string División(int operador1, int operador2)
        {
            int resultado;
            string retorno;
            resultado = operador1 / operador2;
            retorno = resultado.ToString();
            return retorno;
        }
    }
}

提前致谢。

您可以使用 System.Addin 命名空间中的 Managed Addin Framework (MAF) 来执行您所描述的操作。我用它来编写扫描文件夹中的 DLL 并动态加载它们的应用程序。您还可以使用它来卸载和重新加载 DLL,因为它们在文件夹中出现和消失。