Ésta es una respuesta tardía, pero valdría la pena tenerlo aquí para cualquier futuras vistas a esta pregunta. Necesitaba implementar algo similar a esto, pero en una forma de compilación/ejecución de código dinámico. Lo mejor sería ejecutar todos los métodos en un dominio separado, es decir, dominio remoto, que no sea el dominio de aplicación principal, de lo contrario, la memoria de la aplicación siempre aumentará y aumentará. Puede resolver este problema a través de interfaces y proxies remotos. Así expondrías tus métodos a través de una interfaz de la que obtendrás una instancia en tu AppDomain principal y luego ejecutarás remotamente esos métodos en el dominio remoto, descargarás el dominio recién creado (dominio remoto), lo anularás y luego forzarás al GC a recoger objetos no utilizados. Pasé bastante tiempo depurando mi código hasta que me di cuenta de que tenía que forzar al GC a hacerlo y funciona muy bien. A granel de mi implementación se toma desde: http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm.
//pseudo code
object ExecuteCodeDynamically(string code)
{
Create AppDomain my_app
src_code = "using System; using System.Reflection; using RemoteLoader;
namespace MyNameSpace{
public class MyClass:MarshalByRefObject, IRemoteIterface
{
public object Invoke(string local_method, object[] parameters)
{
return this.GetType().InvokeMember(local_method, BindingFlags.InvokeMethod, null, this, parameters);
}
public object ExecuteDynamicCode(params object[] parameters)
{
" + code + } } } ";// this whole big string is the remote application
//compile this code which is src_code
//output it as a DLL on the disk rather than in memory with the name e.g.: DynamicHelper.dll. This can be done by playing with the CompileParameters
// create the factory class in the secondary app-domain
RemoteLoader.RemoteLoaderFactory factory =
(RemoteLoader.RemoteLoaderFactory)loAppDomain.CreateInstance("RemoteLoader",
"RemoteLoader.RemoteLoaderFactory").Unwrap();
// with the help of this factory, we can now create a real instance
object loObject = factory.CreateInstance("DynamicHelper.dll", "MyNamespace.MyClass", null);
// *** Cast the object to the remote interface to avoid loading type info
RemoteLoader.IRemoteInterface loRemote = (RemoteLoader.IRemoteInterface)loObject;
if (loObject == null)
{
System.Windows.Forms.MessageBox.Show("Couldn't load class.");
return null;
}
object[] loCodeParms = new object[1];
loCodeParms[0] = "bla bla bla";
try
{
// *** Indirectly call the remote interface
object result = loRemote.Invoke("ExecuteDynamicCode", loCodeParms);// this is the object to return
}
catch (Exception loError)
{
System.Windows.Forms.MessageBox.Show(loError.Message, "Compiler Demo",
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Information);
return null;
}
loRemote = null;
try { AppDomain.Unload(my_app); }
catch (CannotUnloadAppDomainException ex)
{ String str = ex.Message; }
loAppDomain = null;
GC.Collect();//this will do the trick and free the memory
GC.WaitForPendingFinalizers();
System.IO.File.Delete("ConductorDynamicHelper.dll");
return result;
}
Tenga en cuenta que RemoteLoader es otro DLL que debe ser creado ya y se añade a la vez que la aplicación principal y su aplicación de control remoto. Básicamente es una interfaz y un cargador de fábrica. El código siguiente es tomado de la página web anterior:
/// <summary>
/// Interface that can be run over the remote AppDomain boundary.
/// </summary>
public interface IRemoteInterface
{
object Invoke(string lcMethod,object[] Parameters);
}
naemspace RemoteLoader{
/// <summary>
/// Factory class to create objects exposing IRemoteInterface
/// </summary>
public class RemoteLoaderFactory : MarshalByRefObject
{
private const BindingFlags bfi = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;
public RemoteLoaderFactory() {}
/// <summary> Factory method to create an instance of the type whose name is specified,
/// using the named assembly file and the constructor that best matches the specified parameters. </summary>
/// <param name="assemblyFile"> The name of a file that contains an assembly where the type named typeName is sought. </param>
/// <param name="typeName"> The name of the preferred type. </param>
/// <param name="constructArgs"> An array of arguments that match in number, order, and type the parameters of the constructor to invoke, or null for default constructor. </param>
/// <returns> The return value is the created object represented as ILiveInterface. </returns>
public IRemoteInterface Create(string assemblyFile, string typeName, object[] constructArgs)
{
return (IRemoteInterface) Activator.CreateInstanceFrom(
assemblyFile, typeName, false, bfi, null, constructArgs,
null, null, null).Unwrap();
}
}
}
la esperanza que esto tiene sentido y ayuda ...
¿Podría elaborar un poco más? ¿A qué línea de código se refiere en la publicación de OP? – NGambit
Supongo que se refiere a devolver Assembly.LoadFile (ruta); Y en su lugar, se recomienda algo como byte [] bytes = File.ReadAllBytes (ruta); return assembly = Assembly.Load (bytes); ¿Lo estoy entendiendo correctamente? – NGambit