Reflectionを使用してDllに含まれるいくつかのメソッドをテストするための基本的なWinFormソリューション(MS VS2013、.Net framework 4.5)があります。私の目標は、Dllの2つのメソッド(プロジェクトでdllを参照することなく)を実行できるメインアプリケーションをテストし、その後、メインアプリケーションを停止せずにリフレクションを使用して4つのメソッド(2つのメソッドを追加)を実行することです。実行時にdllを痛みなく置き換える
Reflectionsはうまくいきます(メインアプリケーションを停止し、dllファイルを置き換えてメインアプリケーションを再実行しても問題ありません)、実行時にdllを置き換えることはできません。
メインアプリケーションには、60秒間隔のタイマーコントロールがあります。 60秒ごとに、DLLファイルがフォルダ内にあるかどうかをチェックするメソッドが実行されます。そのDLLファイルがそのフォルダに存在する場合、新しいDLLに古いメソッド(最初のDLL)とメインアプリケーションに必要な追加のメソッドが含まれているため、メインアプリケーション(実行中)で新しいDLLを使用します。 しかし、ファイルが使用中であるというエラーが表示されます。
私はいくつかの投稿、質問、回答、MEFドキュメント、AppDomainsに関連していますが、ソリューションを実装するために情報を連結することができませんでした。
実際、私はこの質問を投稿する前に多くのことを考えましたが、私はあなたが私に手を差し伸べることができることを知っているので、恥ずかしい思いをします。
コードと具体的な指示で私を助けてくれたら大きな助けとなります。
これはコードです:
主な用途:主なアプリケーションのためのいくつかの機能のためのプロジェクトで
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;
}
}
}
はクラス、:
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;
}
}
}
事前に感謝します。
同様の質問に対する回答を見てください:http://stackoverflow.com/questions/18362368/loading-dlls-at-runtime-in-c-sharp –
それに似ていますが、参照されるポストロードはユニークですdllであり、実行時に別のDLLをロードする必要はありません@EdPower – Gabms
唯一の選択肢は、そのアセンブリを新しいAppDomainにロードすることです。読書を自分でやりたいのであれば、読んでみてください。https://msdn.microsoft.com/en-us/library/yb506139(v=vs.110).aspxとhttps://blogs.msdn.microsoft .com/suzcook/2003 /は良い出発点です。 http://stackoverflow.com/questions/658498/how-to-load-an-assembly-to-appdomain-with-all-references-recursivelyのようなものは、コードを助けることができます... –