这是一个较晚的答案,但对于未来对此问题的任何看法都是值得的。我需要以动态代码编译/执行方式实现与此类似的东西。
最好是在一个单独的域中执行所有方法,即:远程域,而不是您的主 AppDomain,否则应用程序内存将始终增加和增加。您可以通过远程接口和代理解决此问题。
因此,您将通过一个接口公开您的方法,您将在主 AppDomain 中获得一个实例,然后在远程域中远程执行这些方法,卸载新创建的域(远程域),将其无效,然后强制 GC 收集未使用的对象。我花了很长时间调试我的代码,直到我意识到我必须强制 GC 这样做并且它工作得很好。我的大部分实现来自: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;
}
请注意,RemoteLoader 是另一个应该已经创建并添加到主应用程序和远程应用程序的 DLL。它基本上是一个接口和一个工厂加载器。以下代码取自上述网站:
/// <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();
}
}
}
希望这有意义并有所帮助......