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

时间:2015-05-12 21:12:13

标签: c# multithreading reflection.emit

我想在运行时创建类型并通过Activator.CreateInstance实例化它。我正在使用Refletion.Emit做它并且当创建和实例化类型的方法在单个线程中运行时,everithing工作正常。但是,当我尝试在多个线程中运行相同的方法时,抛出了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

1 个答案:

答案 0 :(得分:3)

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

在您的代码中,GetDynamicType不是线程安全的,有两种竞争条件无法处理。它们中更有趣的是:

一个线程使用ModuleBuilder.DefineType(...)定义新类型。它获取TypeBuilder对象,然后用它来构建类型。

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

只有当第一个帖子调用TypeBuilder.CreateType()时,TypeBuilder才会被RuntimeType中的相应ModuleBuilder替换。

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

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

  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);
  }