使用具有静态变量的 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);
    }
}