私はIL生成を使用して、Luceneドキュメントから文字列を取り出し、参照型オブジェクト(POCO)のプロパティまたはフィールドを設定する単純なデシリアライザーメソッドを作成しています。
生成されたメソッドを実行しようとすると、VerificationExceptionエラーが発生します。このエラーに関して他にも質問があり、そのうちのいくつかはDynamicMethodsに関係していますが、私が抱えている問題とは異なります。
operation-could-destablize-the-runtime-and-dynamicmethod-with-value-types
msil-operation-could-destabilize-the-runtime-exception
この方法は将来さらに複雑になりますが、今は文字列の割り当てを行っているだけです。私が動的に作成しようとしているメソッドは、次のようになります。
public static PocoObject ExampleMethod(Document document)
{
var poco = new PocoObject();
poco.ID = document.Get("ID");
poco.DisplayText = document.Get("DisplayText");
poco.PropId = document.Get("PropId");
return poco;
}
PocoObjectは次のようになります。
class PocoObject
{
public string ID;
public string DisplayText;
public string PropId { get; set; }
}
コンパイル時のコードから生成されたILを正確に(不要なビットも)複製しようとしましたが、次のようになります。
.method public instance object 'Deserializebe6d500b-d35f-4f7a-a9b3-88f6bca5fb93'(class [Lucene.Net]Lucene.Net.Documents.Document A_1) cil managed
{
// Code size 65 (0x41)
.maxstack 4
IL_0000: nop
IL_0001: newobj instance void [LukeMapperTest]LukeMapperTest.PocoObject::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldarg.0
IL_0009: ldstr "ID"
IL_000e: callvirt instance string [Lucene.Net]Lucene.Net.Documents.Document::Get(string)
IL_0013: stfld string [LukeMapperTest]LukeMapperTest.PocoObject::ID
IL_0018: ldloc.0
IL_0019: ldarg.0
IL_001a: ldstr "DisplayText"
IL_001f: callvirt instance string [Lucene.Net]Lucene.Net.Documents.Document::Get(string)
IL_0024: stfld string [LukeMapperTest]LukeMapperTest.PocoObject::DisplayText
IL_0029: ldloc.0
IL_002a: ldarg.0
IL_002b: ldstr "PropId"
IL_0030: callvirt instance string [Lucene.Net]Lucene.Net.Documents.Document::Get(string)
IL_0035: callvirt instance void [LukeMapperTest]LukeMapperTest.PocoObject::set_PropId(string)
IL_003a: nop
IL_003b: ldloc.0
IL_003c: stloc.1
IL_003d: br.s IL_003f
IL_003f: ldloc.1
IL_0040: ret
} // end of method Test::'Deserializebe6d500b-d35f-4f7a-a9b3-88f6bca5fb93'
DynamicMethodをディスク上のアセンブリに保存して検査しましたが、これがまさにその結果です。行ごとに、コンパイル時のメソッドILと同じです。
それでも、動的メソッドを実行すると、上記のエラーがスローされます。誰かが私がこれを修正する方法を知っていますか?
注:誰かが詳しく調べたい場合は、GitHubにソースコードがあります。IL生成コードはLukeMapper.cs:GetDumbDeserializer()にあります(133行目)
すべての助けに感謝します!ありがとう!
編集:それで私はIL生成コードを単純化しました、そしてそれは本質的に次のとおりです:
private static Func<Document, object> GetDumbDeserializer(Type type)
{
var dm = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), typeof(object), new[] { typeof(Document) }, true);
var il = dm.GetILGenerator();
var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
il.Emit(OpCodes.Nop);
il.DeclareLocal(type);
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_0);
Label returnLabel = il.DefineLabel();
//stack is [target]
var getFieldValue = typeof(Document).GetMethod("Get", BindingFlags.Instance | BindingFlags.Public);
foreach (var setter in settableProperties)
{
il.Emit(OpCodes.Ldloc_0);// [target]
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, setter.Name);
il.Emit(OpCodes.Callvirt, getFieldValue);
il.Emit(OpCodes.Stfld, setter.Field);
}
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Stloc_1); // stack is empty
il.Emit(OpCodes.Br_S, returnLabel);
il.MarkLabel(returnLabel);
il.Emit(OpCodes.Ldloc_1); // stack is [rval]
il.Emit(OpCodes.Ret);
return (Func<Document, object>)dm.CreateDelegate(typeof(Func<Document, object>));
}
il.DeclareLocal(type)
kvbsのコメントごとに(typeはPocoObject)を追加しましたが、適切な場所に配置しているかどうか(または重要かどうか)はわかりません。