我有一个DLL,(我无法改变!),它有静态变量。
我想调用Activator.CreateInstance(...)
但是创建一个全新的实例,而不是共享以前加载的实例。
// ClassLibrary.dll
namespace ClassLibrary
{
public class Foo
{
private static int Number { get; set; } // This is a static member...
public Foo()
{
Number++;
}
public int Bar()
{
return Number;
}
}
}
// ConsoleApplication.exe
static int InvokeMethod()
{
var dir = Directory.GetCurrentDirectory();
var path = Path.Combine(dir, "ClassLibrary.dll");
var asm = Assembly.LoadFile(path);
var type = asm.GetType("ClassLibrary.Foo");
var instance = Activator.CreateInstance(type, new object[] { });
var method = type.GetMethod("Bar");
return (int)method.Invoke(instance, null);
}
private static void Main(string[] args)
{
var val1 = InvokeMethod(); // 1
var val2 = InvokeMethod(); // 2! I want it to be 1
}
我尝试使用AppDomain.Load()
,但静态值仍在分享。
有关如何加载全新实例而不是共享以前加载的dll的任何建议。
编辑1 :这是AppDomain加载的代码,但结果是一样的。
static int InvokeMethodDomain()
{
var dir = Directory.GetCurrentDirectory();
var path = Path.Combine(dir, "ClassLibrary.dll");
var dom = AppDomain.CreateDomain(Guid.NewGuid().ToString());
try
{
var asn = new AssemblyName {CodeBase = path};
var asm = dom.Load(asn);
var type = asm.GetType("ClassLibrary.Foo");
var instance = Activator.CreateInstance(type, new object[] { });
var method = type.GetMethod("Bar");
return (int) method.Invoke(instance, null);
}
finally
{
AppDomain.Unload(dom);
}
}
答案 0 :(得分:2)
正如您已经想到的那样,您需要将程序集加载到新的应用程序域中以获取新的静态值。示例代码:
// inherit from MarshalByRefObject to enable cross domain communication
public class AppDomainProxy : MarshalByRefObject {
public int InvokeMethod() {
var dir = AppDomain.CurrentDomain.BaseDirectory;
var path = Path.Combine(dir, "ClassLibrary.dll");
var asm = Assembly.LoadFile(path);
var type = asm.GetType("ClassLibrary.Foo");
var instance = Activator.CreateInstance(type, new object[] { });
var method = type.GetMethod("Bar");
return (int) method.Invoke(instance, null);
}
}
然后:
static int InvokeMethod()
{
var appDomain = AppDomain.CreateDomain("Domain", AppDomain.CurrentDomain.Evidence, new AppDomainSetup {
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory
});
try {
// first create our proxy
var instance = (AppDomainProxy) appDomain.CreateInstanceAndUnwrap(
typeof(AppDomainProxy).Assembly.FullName,
typeof(AppDomainProxy).FullName);
// this will run in new app domain
return instance.InvokeMethod();
}
finally {
AppDomain.Unload(appDomain);
}
}