J'essaie de créer un champ statique à l'aide de Reflection.Emit.Comment créer un champ statique à l'aide de Reflection.Emit
Cependant, j'obtiens une exception InvalidProgramException lorsque j'essaie de le charger.
Le code suivant reproduit mon problème.
La ligne:
generator.Emit(OpCodes.Ldsfld, builderField);
provoque l'exception suivante:
Unhandled Exception: System.InvalidProgramException: Common Language Runtime detected an invalid program.
sans cette ligne le programme fonctionne très bien et retourne "Test" comme prévu
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName(Guid.NewGuid().ToString()),
AssemblyBuilderAccess.Run);
var module = assemblyBuilder.DefineDynamicModule("module1");
var typeBuilder = module.DefineType("MyType", TypeAttributes.Public|TypeAttributes.Class);
typeBuilder.AddInterfaceImplementation(typeof(IMyType));
var builderField = typeBuilder.DefineField("_builder", typeof(StringBuilder), FieldAttributes.Static | FieldAttributes.Private);
var methodBuilder = typeBuilder.DefineMethod(
"UseStringBuilder",
MethodAttributes.Public | MethodAttributes.Virtual,
typeof(string),
new Type[0]);
var generator = methodBuilder.GetILGenerator();
//this line causes InvalidProgramException, without this line it works
generator.Emit(OpCodes.Ldsfld, builderField);
generator.Emit(OpCodes.Ldstr, "Test");
generator.Emit(OpCodes.Ret);
var typeInfo = typeBuilder.CreateTypeInfo();
var myType = typeInfo.AsType();
IMyType instance = (IMyType)Activator.CreateInstance(myType);
instance.UseStringBuilder();
Je sais que je n'utilise pas le StringBuilder pour quelque chose juste en le mettant sur la pile, et qu'il sera nul comme il s non initialisé, cependant c'est une version simplifiée (dans le but de reproduire le problème) d'un programme plus grand qui paresseux initialise le champ, donc j'ai besoin de le charger sur la pile pour que je puisse le vérifier pour null. Cependant, l'instruction ldsfld bloque le programme avant que je puisse faire cela.
ILSPY pour une version de travail de ce code ressemble à ceci:
// Fields
.field private static class [System.Runtime]System.Text.StringBuilder _builder
// Methods
.method public final hidebysig newslot virtual
instance string UseStringBuilder() cil managed
{
// Method begins at RVA 0x20ee
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldsfld class [System.Runtime]System.Text.StringBuilder JsonicsTests.MyType::_builder
IL_0005: brtrue.s IL_0011
IL_0007: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor()
IL_000c: stsfld class [System.Runtime]System.Text.StringBuilder JsonicsTests.MyType::_builder
IL_0011: ldsfld class [System.Runtime]System.Text.StringBuilder JsonicsTests.MyType::_builder
IL_0016: callvirt instance string [System.Runtime]System.Object::ToString()
IL_001b: ret
}
Quelle est la bonne façon de créer et d'utiliser un champ statique à l'aide Reflection.Emit? J'utilise .net core 1.1 sur Linux si cela est pertinent.
Cela l'a corrigé. Je savais qu'il y avait quelque chose de fondamental qui me manquait. Ma question semble maintenant de faible valeur, devrais-je la supprimer? – trampster
@trampster Je pense que votre question est très intéressante. Le fait que la pile doit être vide/doit avoir une seule valeur (si vous avez besoin de la retourner) à la fin d'une fonction générée est quelque chose de très important qui n'est pas écrit assez fortement dans les tutoriels sur la génération de code. – xanatos