我想在运行时创建类型,并通过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();
}
}
}
一些观察:
更新1:
异常消息是:“类型必须是运行时提供的类型。”
更新2:
完整的源代码托管在GitHub上
最佳答案
也许答案很晚,但是无论如何。
在您的代码中,GetDynamicType
不是线程安全的,有两个未处理的竞争条件。其中更有趣的如下:
一个线程使用ModuleBuilder.DefineType(...)
定义了一种新类型。它获取TypeBuilder
对象,然后将其用于构建类型。
同时,另一个线程调用ModuleBuilder.GetType(...)
并获取它寻找的Type
对象……至少它是这样认为的。假定它得到了RuntimeType
,但是实际上,它得到了第一个线程正在构建的TypeBuilder
。
仅当第一个线程调用TypeBuilder.CreateType()
时,才会将TypeBuilder
替换为RuntimeType
中的相应ModuleBuilder
。
因此,您最终尝试输入Activator.CreateInstance
的TypeBuilder
,从而引发“类型必须是运行时提供的类型”异常。
我建议重写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/