Simon Goodman
Simon Goodman

Reputation: 1204

Calling Activator.Createinstance(...) with DLL that has static variable

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

Answers (1)

Evk
Evk

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

Related Questions