使用具有静态变量的 DLL 调用 Activator.Createinstance(...)
Calling Activator.Createinstance(...) with DLL that has static variable
我有一个 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);
}
}
如您所知,您需要将程序集加载到新的应用程序域中以获取新的静态值。示例代码:
// 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);
}
}
我有一个 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);
}
}
如您所知,您需要将程序集加载到新的应用程序域中以获取新的静态值。示例代码:
// 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);
}
}