Reputation: 1204
I have a DLL, (that I cannot change!), that has static variable.
I want to call Activator.CreateInstance(...)
but create a brand new Instance rather than share a previously loaded Instance.
// 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
}
I have tried the same with AppDomain.Load()
, but the static value is still being shared.
Any suggestions on how I can load a brand new instance rather than sharing the previously loaded dll.
Edit 1: Here is the code of the AppDomain load, but the result is the same.
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);
}
}
Upvotes: 0
Views: 1666
Reputation: 101483
As you already figured out, you need to load assembly into new app domain to get fresh static values. Sample code:
// 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);
}
}
And then:
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);
}
}
Upvotes: 3