2013-08-22 2 views
3

У меня есть динамический модуль, который получает типы, добавленные к нему, когда мое приложение запускается. Модуль создан с помощью следующего кода:Когда динамический модуль может иметь исключение нагрузки типа?

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() вызывается, а тип - частично через создание?

EDIT: вот небольшой фрагмент кода, который достоверно воспроизводит ошибку для меня. Теперь кажется, что исключение возникает, если GetTypes() вызывается между DefineType() и CreateType():

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

ответ