我想在运行时创建类型,并通过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替换为RuntimeType中的相应ModuleBuilder

    因此,您最终尝试输入Activator.CreateInstanceTypeBuilder,从而引发“类型必须是运行时提供的类型”异常。

    我建议重写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);
      }
    

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

    10-11 02:06