Hi, I'm writing some code that will create some static methods for a dynamically created assembly. One method is giving me an InvalidProgramException when run.
The code that I am trying to generate, from C# is:
A simple method that will take a Type, a bool and return true if it finds a string that is paired with that Type.
The code to generate this is:
mb = typeBuilder.DefineMethod("TryGetName",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static,
typeof(bool), new[] { typeof(Type), typeof(bool), typeof(string).MakeByRefType() });
mb.DefineParameter(1, ParameterAttributes.None, "type");
mb.DefineParameter(2, ParameterAttributes.None, "asCompiled");
mb.DefineParameter(3, ParameterAttributes.Out, "name");
ILGenerator tryGetNameIL = mb.GetILGenerator();
LocalBuilder tryGetName_pairLocal = tryGetNameIL.DeclareLocal(typeof(KeyValuePair<string,>));
LocalBuilder tryGetName_enumLocal = tryGetNameIL.DeclareLocal(typeof (Dictionary<string,>.Enumerator));
LocalBuilder tryGetName_resLocal = tryGetNameIL.DeclareLocal(typeof (bool));
Label tryGetName_endLoopLabel = tryGetNameIL.DefineLabel();
Label tryGetName_startLoopLabel = tryGetNameIL.DefineLabel();
Label tryGetName_endStringReplaceLabel = tryGetNameIL.DefineLabel();
Label tryGetName_endOfMethod = tryGetNameIL.DefineLabel();
tryGetNameIL.Emit(OpCodes.Ldfld, typesFieldBuilder);
tryGetNameIL.EmitCall(OpCodes.Callvirt, typesFieldBuilder.FieldType.GetMethod("GetEnumerator", Type.EmptyTypes), null);
tryGetNameIL.Emit(OpCodes.Stloc, tryGetName_enumLocal);
tryGetNameIL.BeginExceptionBlock();
tryGetNameIL.Emit(OpCodes.Br_S, tryGetName_endLoopLabel);
tryGetNameIL.MarkLabel(tryGetName_startLoopLabel);
tryGetNameIL.Emit(OpCodes.Ldloca_S, tryGetName_enumLocal);
tryGetNameIL.EmitCall(OpCodes.Call, tryGetName_enumLocal.LocalType.GetProperty("Current").GetGetMethod(), null);
tryGetNameIL.Emit(OpCodes.Stloc, tryGetName_pairLocal);
tryGetNameIL.Emit(OpCodes.Ldloca_S, tryGetName_pairLocal);
tryGetNameIL.EmitCall(OpCodes.Call, tryGetName_pairLocal.LocalType.GetProperty("Value").GetGetMethod(), null);
tryGetNameIL.Emit(OpCodes.Ldarg_0);
tryGetNameIL.Emit(OpCodes.Ceq);
tryGetNameIL.Emit(OpCodes.Brfalse_S, tryGetName_endLoopLabel);
tryGetNameIL.Emit(OpCodes.Ldarg_2);
tryGetNameIL.Emit(OpCodes.Ldloca_S, tryGetName_pairLocal);
tryGetNameIL.EmitCall(OpCodes.Call, tryGetName_pairLocal.LocalType.GetProperty("Key").GetGetMethod(), null);
tryGetNameIL.Emit(OpCodes.Stind_Ref);
tryGetNameIL.Emit(OpCodes.Ldarg_1);
tryGetNameIL.Emit(OpCodes.Brfalse_S, tryGetName_endStringReplaceLabel);
tryGetNameIL.Emit(OpCodes.Ldarg_2);
tryGetNameIL.Emit(OpCodes.Dup);
tryGetNameIL.Emit(OpCodes.Ldind_Ref);
tryGetNameIL.Emit(OpCodes.Ldstr, "-");
tryGetNameIL.Emit(OpCodes.Ldstr, "::");
tryGetNameIL.EmitCall(OpCodes.Callvirt, typeof(string).GetMethod("Replace", new [] {typeof(string), typeof(string)}), null);
tryGetNameIL.Emit(OpCodes.Stind_Ref);
tryGetNameIL.MarkLabel(tryGetName_endStringReplaceLabel);
tryGetNameIL.Emit(OpCodes.Ldc_I4_1);
tryGetNameIL.Emit(OpCodes.Stloc, tryGetName_resLocal);
tryGetNameIL.Emit(OpCodes.Leave_S, tryGetName_endOfMethod);
tryGetNameIL.MarkLabel(tryGetName_endLoopLabel);
tryGetNameIL.Emit(OpCodes.Ldloca_S, tryGetName_enumLocal);
tryGetNameIL.EmitCall(OpCodes.Call, tryGetName_enumLocal.LocalType.GetMethod("MoveNext"), null);
tryGetNameIL.Emit(OpCodes.Brtrue_S, tryGetName_startLoopLabel);
tryGetNameIL.BeginFinallyBlock();
tryGetNameIL.Emit(OpCodes.Ldloca_S, tryGetName_enumLocal);
tryGetNameIL.Emit(OpCodes.Constrained, tryGetName_enumLocal.LocalType);
tryGetNameIL.EmitCall(OpCodes.Callvirt, typeof(IDisposable).GetMethod("Dispose"), null);
tryGetNameIL.EndExceptionBlock();
tryGetNameIL.Emit(OpCodes.Ldarg_2);
tryGetNameIL.Emit(OpCodes.Ldnull);
tryGetNameIL.Emit(OpCodes.Stind_Ref);
tryGetNameIL.Emit(OpCodes.Ldc_I4_0);
tryGetNameIL.Emit(OpCodes.Stloc, tryGetName_resLocal);
tryGetNameIL.MarkLabel(tryGetName_endOfMethod);
tryGetNameIL.Emit(OpCodes.Ldloc, tryGetName_resLocal);
tryGetNameIL.Emit(OpCodes.Ret);
And this, when run, creates the following IL:
.method public hidebysig static bool TryGetName(class [mscorlib]System.Type 'type',
bool asCompiled,
[out] string& name) cil managed
{
.maxstack 9
.locals init (valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<string,class> V_0,
valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,class> V_1,
bool V_2)
IL_0000: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,class> BlueprintSchema.BlueprintNameMapping::types
IL_0005: callvirt instance valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator class [mscorlib]System.Collections.Generic.Dictionary`2<string,class>::GetEnumerator()
IL_000a: stloc.1
.try
{
IL_000b: br.s IL_0044
IL_000d: ldloca.s V_1
IL_000f: call instance valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2 valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,class>::get_Current()
IL_0014: stloc.0
IL_0015: ldloca.s V_0
IL_0017: call instance !1 valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<string,class>::get_Value()
IL_001c: ldarg.0
IL_001d: ceq
IL_001f: brfalse.s IL_0044
IL_0021: ldarg.2
IL_0022: ldloca.s V_0
IL_0024: call instance !0 valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<string,class>::get_Key()
IL_0029: stind.ref
IL_002a: ldarg.1
IL_002b: brfalse.s IL_0040
IL_002d: ldarg.2
IL_002e: dup
IL_002f: ldind.ref
IL_0030: ldstr "-"
IL_0035: ldstr "::"
IL_003a: callvirt instance string [mscorlib]System.String::Replace(string,
string)
IL_003f: stind.ref
IL_0040: ldc.i4.1
IL_0041: stloc.2
IL_0042: leave.s IL_0065
IL_0044: ldloca.s V_1
IL_0046: call instance bool valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,class>::MoveNext()
IL_004b: brtrue.s IL_000d
IL_004d: leave IL_0060
}
finally
{
IL_0052: ldloca.s V_1
IL_0054: constrained. valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,class>
IL_005a: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_005f: endfinally
}
IL_0060: ldarg.2
IL_0061: ldnull
IL_0062: stind.ref
IL_0063: ldc.i4.0
IL_0064: stloc.2
IL_0065: ldloc.2
IL_0066: ret
}
When run (e.g. calling BlueprintNameMapping.TryGetValue(typeof(Blueprints.cEngineBlueprint), true, out name); where Blueprint.cEngineBlueprint is some class not related to this), I simply get an InvalidProgramException with absolutely no clue as to where the error occured. I have read this occurs when IL is converted to native code. I have narrowed the problem down up to this method and cannot work out where it could be going wrong.
Thanks,
Ben
|