c# - 从 TypeBuilder.CreateType 返回的类型的 Activator.CreateInstance 抛出 ArgumentException

标签 c# multithreading reflection.emit

我想在运行时创建类型并通过 Activator.CreateInstance 实例化它。我正在使用 Refletion.Emit 来执行此操作,当创建和实例化类型的方法在单个线程中运行时,一切正常。然而,当我尝试在多个线程中运行相同的方法时,会抛出一个 ArgumentException。

代码类似于:

class TypeBuilder
  public IMyType Build() {
    Type type = GetDynamicType("MyDynamicType");
    IMyType myType = (IMyType) Activator.CreateInstance(type);
    return myType;
  }

  Type GetDynamicType(string typeName) {
    // define the module builder...
    ModuleBuilder module = ...
    Type type = module.GetType(typeName);
    if (type == null) {
      type = MakeDynamicType(typeName);
    }
    retyrn type;
  }

  Type MakeDynamicType(string typeName) {
     lock(lock_) { // lock_ is a static variable
        // ensure that the type was not already created by another thread.
        Type type =
           module
            .GetType(typeName);
        if (type != null) {
          return type;
        }
       // define the type builder...
       TypeBuilder builder = ...

       // define the type body...

       return type.CreateType();
     }
  }
}

一些观察:

  • 仅当多个线程尝试创建该类型时才会抛出异常。
  • 第一次调用该方法并抛出异常时,返回的类型派生自 TypeBuilder 而不是 RunTimeType,但第二次调用该方法时,该类型派生自 RunTimeType。

更新 1:

异常消息是:“类型必须是运行时提供的类型。”

更新 2:

完整的源代码托管在 GitHub

最佳答案

也许是一个迟到的答案,但无论如何。

在您的代码中,GetDynamicType不是线程安全的,有两个未处理的竞争条件。其中比较有趣的是:

一个线程用ModuleBuilder.DefineType(...)定义了一个新类型.它得到 TypeBuilder然后使用它来构建类型的对象。

同时,另一个线程调用ModuleBuilder.GetType(...)并获得 Type它寻找的对象……至少它是这么认为的。它假设它得到了 RuntimeType ,但实际上,它得到了 TypeBuilder由第一个线程构建。

仅当第一个线程调用TypeBuilder.CreateType()时, TypeBuilder替换为相应的 RuntimeTypeModuleBuilder .

所以你最终会尝试 Activator.CreateInstanceTypeBuilder ,它会抛出“类型必须是运行时提供的类型”异常。

我建议重写 GetDynamicType函数并使用 ConcurrentDictionary<string, Type>MakeDynamicType作为值(value)工厂:

  private readonly ConcurrentDictionary<string, Type> _dynamicTypesByName = 
      new ConcurrentDictionary<string, Type>();

  Type GetDynamicType(string typeName) {
    // define the module builder...
    ModuleBuilder module = ...
    return _dynamicTypesByName.GetOrAdd(typeName, MakeDynamicType);
  }

关于c# - 从 TypeBuilder.CreateType 返回的类型的 Activator.CreateInstance 抛出 ArgumentException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30201509/

相关文章:

c# - 隐藏 TabControl 按钮以管理堆叠的面板控件

c# - NHibernate.查询异常 : could not resolve property - Column name with ID

reflection - 使用 Reflection.Emit 生成可识别联合

c# - ILGenerator 捕获异常不起作用

c# - 从动态创建的类中调用构造函数和方法

c# - 奇怪的 : WinForms form closes automatically after button press

c# - 如何在运行时生成 lambda 将属性名称作为字符串传递?

multithreading - 捕获异步 bash 命令的输出?

java - 同步关键字在内部如何工作

c++ - 是否可以使用单独的线程来读取和写入 Boost.Asio?