动态模块什么时候会出现类型加载异常?

问题描述 投票:0回答:2

我有一个动态模块,当我的应用程序运行时,它会添加类型。该模块是通过以下代码创建的:

var assemblyName = new AssemblyName("MyAssembly");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
MyClass.RuntimeBoundDerivedTypesModule = assemblyBuilder.DefineDynamicModule("MainModule");

应用程序的其他部分有时也会在模块的程序集中调用 GetTypes()。有时,当发生这种情况时,我会收到动态模块中的其中一种类型的 TypeLoadException。堆栈跟踪是:

   at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
   at System.Reflection.RuntimeModule.GetTypes()
   at System.Reflection.Assembly.GetTypes()

我的问题是:什么可能导致此异常?运行时模块是否真正是线程安全的,或者是否存在在类型创建过程中调用 GetTypes() 的竞争条件?

编辑:这是一小段代码,可以为我可靠地重现该错误。现在看来,如果在DefineType()和CreateType()之间调用GetTypes()就会出现异常:

var assemblyName = new AssemblyName("MyAssembly");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder m = assemblyBuilder.DefineDynamicModule("foo");

Action doStuff = () => {
    try {
        if (!m.GetTypes().Any() || Guid.NewGuid().GetHashCode() % 2 == 0) {
            var t = m.DefineType(
                "MyType" + Guid.NewGuid().ToString().Replace("-", ""),
                TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout,
                typeof(object)
            );
            Thread.Sleep(1);
            t.CreateType();
        }
        else {
            //m.GetTypes(); // interestingly, this always works
            assemblyBuilder.GetTypes();
            "it worked!".Dump();
        }

    } catch (Exception ex) {
        Console.WriteLine(ex);
    }
};

// in synchronous mode, I only see failures if I leave out the call to CreateType(). In that
// case, it never works
//Enumerable.Range(1, 1000)
//  .ToList()
//  .ForEach(_ => doStuff());

// in the async mode, I always see failures with Thread.Sleep() and sometimes
// see them if I take the sleep out. I often see a mix of failures and "It worked!"
var threads = Enumerable.Range(1, 100).Select(t => new Thread(() => doStuff()))
    .ToList();
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());
c# reflection typeloadexception dynamic-assemblies
2个回答
0
投票

ModuleBuilder 以及事实上大多数实例方法在 .Net 中都不是线程安全的。请参阅底部:http://msdn.microsoft.com/en-us/library/system.reflection.emit.modulebuilder.aspx


0
投票

有点死灵帖子,但它可能会帮助未来遇到类似问题的人找到此线程。

昨天我遇到了类似的问题,只不过我不在线程场景中。显然,如果调用了

TypeLoadException
,也可以抛出
DefineType
,但
CreateType
则不会。如果在这两个调用之间抛出异常,则很容易发生这种情况,这就是我的场景中发生的情况。我有一个抛出异常的合理案例,因为我正在构建的类型被证明无法针对给定参数构建。解决方案是在尝试之前准备好所有必需的信息并对其进行验证
DefineType

© www.soinside.com 2019 - 2024. All rights reserved.