Ten fragment kodu jest uproszczony wyciąg z mojego kodu klasy generacji, która tworzy dwie klasy, które odwołują się do siebie jako argumenty w rodzaju ogólnego:Dlaczego otrzymuję ten wyjątek podczas emitowania klas, które odwołują się do siebie za pośrednictwem generycznych typów wartości?
namespace Sandbox
{
using System;
using System.Reflection;
using System.Reflection.Emit;
internal class Program
{
private static void Main(string[] args)
{
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule("Test");
var typeOne = module.DefineType("TypeOne", TypeAttributes.Public);
var typeTwo = module.DefineType("TypeTwo", TypeAttributes.Public);
typeOne.DefineField("Two", typeof(TestGeneric<>).MakeGenericType(typeTwo), FieldAttributes.Public);
typeTwo.DefineField("One", typeof(TestGeneric<>).MakeGenericType(typeOne), FieldAttributes.Public);
typeOne.CreateType();
typeTwo.CreateType();
Console.WriteLine("Done");
Console.ReadLine();
}
}
public struct TestGeneric<T>
{
}
}
Które powinny produkować równowartość MSIL do następujących:
public class TypeOne
{
public Program.TestGeneric<TypeTwo> Two;
}
public class TypeTwo
{
public Program.TestGeneric<TypeOne> One;
}
Ale zamiast rzuca ten wyjątek na linii typeOne.CreateType()
:
System.TypeLoadException was unhandled
Message=Could not load type 'TypeTwo' from assembly 'Test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
Source=mscorlib
TypeName=TypeTwo
StackTrace:
at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.TypeBuilder.CreateType()
at Sandbox.Program.Main(String[] args) in C:\Users\aca1\Code\Sandbox\Program.cs:line 20
turystyczne Uwagi:
- Odwołanie nie jest wymagane, aby spowodować wyjątek; jeśli nie zdefiniuję pola
One
naTypeTwo
, tworzenieTypeOne
przedTypeTwo
nadal się nie powiedzie, ale utworzenieTypeTwo
przedTypeOne
powiedzie się. Dlatego wyjątek jest w szczególności spowodowany użyciem typu, który nie został jeszcze utworzony jako argument w typowym polu; jednak, ponieważ muszę użyć odwołania cyklicznego, nie mogę uniknąć tej sytuacji, tworząc typy w określonej kolejności. - Tak, I do trzeba użyć okrągłego odniesienia.
- Usuwanie typu opakowania
TestGeneric<>
i zadeklarowanie pól jakoTypeOne
&TypeTwo
bezpośrednio nie powoduje wystąpienia tego błędu; w ten sposób mogę użyć dynamicznych typów, które zostały zdefiniowane, ale nie zostały utworzone. - Zmiana
TestGeneric<>
zstruct
naclass
nie powoduje wystąpienia tego błędu; więc ten wzorzec działa z większością typów generycznych, a nie generycznych. - Nie mogę zmienić deklaracji
TestGeneric<>
w moim przypadku, ponieważ jest zadeklarowany w innym zestawie - konkretnie,System.Data.Linq.EntityRef<>
zadeklarowanym w System.Data.Linq.dll. - Moje odwołanie cykliczne jest spowodowane reprezentowaniem dwóch tabel z przypisanymi do nich kluczami obcymi; stąd potrzeba tego specyficznego typu generycznego i tego konkretnego wzorca.
- Zmiana odniesienia cyklicznego do samodzielnego odniesienia edycja edycja kończy się sukcesem. To nie powiodło się pierwotnie, ponieważ miałem
TestGeneric<>
jako typ zagnieżdżony w Programie, więc odziedziczyło widocznośćinternal
. Naprawiłem to teraz w powyższym przykładzie kodu, i faktycznie działa. - Kompilowanie wygenerowanego kodu ręcznie (jako kod C#) również działa, więc nie jest to problem niejasny dla kompilatora.
Wszelkie pomysły na a) dlaczego tak się dzieje, b) jak mogę to naprawić i/lub c) jak mogę obejść to?
Dzięki.
Ciekawe; tak naprawdę tworzysz typeTwo wewnątrz TypeResolver, co powoduje, że jest on tworzony w połowie tworzonego typeOne, ale wystarczająco późno, by środowisko wykonawcze działało na typeOne. Podstawą tego kodu jest to, że oba typy muszą być w pełni zdefiniowane, zanim można je utworzyć; Zdarza się, że robię to w tym przykładzie, ale muszę upewnić się, że wymuszam to w moim kodzie produkcyjnym. W każdym razie to rozwiązuje mój problem, więc dziękuję! – FacticiusVir
Cieszę się, że mogę Ci pomóc. Był to szczególnie zabawny/interesujący problem, na który warto zwrócić uwagę. Rzeczywiście, typy, które są zaangażowane w cykliczną relację, muszą być gotowe do utworzenia w tym samym momencie. Dziękuję za wskazanie tego. – Scott