Search code examples
c#multithreadingreflection.emit

Activator.CreateInstance of Type returned from TypeBuilder.CreateType throws ArgumentException


I want to create types at Runtime and instantiate it via Activator.CreateInstance. I am using Refletion.Emit to do it and everithing works fine when the method that creates and instantiates the type runs in a single thread. Hoever, when I try to run the same method in more than one thread an ArgumentException is thrown.

The code is similar to:

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

Some observations:

  • The exception is thrown only when more that one thread try to create the type.
  • The first time the method is called and a exception is throw the returned type derives from TypeBuilder and not from RunTimeType, but the second time the method is called the type derives from RunTimeType.

Update 1:

The exception message is : "Type must be a type provided by the runtime."

Update 2:

The full source is hosted on GitHub


Solution

  • Maybe a late answer, but in any way.

    In your code, GetDynamicType is not thread safe, there are two race conditions which aren't handled. The more interesting of them is as follows:

    One thread defines a new type with ModuleBuilder.DefineType(...). It gets TypeBuilder object which it then uses to build the type.

    At the same time, the other thread calls ModuleBuilder.GetType(...) and gets the Type object it looks for... at least it thinks so. It assumes it got the RuntimeType, but actually, it gets the TypeBuilder being built by the first thread.

    Only when the first thread calls TypeBuilder.CreateType(), the TypeBuilder is replaced with the corresponding RuntimeType in the ModuleBuilder.

    And so you end up with trying to Activator.CreateInstance of a TypeBuilder, which throws the "Type must be a type provided by the runtime" exception.

    I would suggest rewriting GetDynamicType function and use a ConcurrentDictionary<string, Type> with MakeDynamicType as value factory:

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