W języku Microsoft IL, aby wywołać metodę typu wartości, potrzebne jest odwołanie pośrednie. Powiedzmy mamy ILGenerator nazwie „il”, a obecnie mamy pustych na wierzchu stosu, jeśli chcemy, by sprawdzić, czy to ma wartość wtedy możemy emitować następujące:Czy jest możliwe pośrednie ładowanie typu wartości na stosie
var local = il.DeclareLocal(typeof(Nullable<int>));
il.Emit(OpCodes.Stloc, local);
il.Emit(OpCodes.Ldloca, local);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
jednak, że będzie byłoby miło, aby pominąć zapisywanie go jako zmiennej lokalnej, a po prostu wywołać metodę na adres zmiennej już na stosie, coś jak:
il.Emit(/* not sure */);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
rodzina ldind instrukcji wygląda obiecująco (szczególnie ldind_ref), ale nie mogę znaleźć wystarczającej dokumentacji, aby wiedzieć, czy spowodowałoby to boksowanie wartości, co podejrzewam, że może.
Miałem przyjrzeć się kompilacji C#, ale używa zmiennych lokalnych do osiągnięcia tego, co pozwala mi wierzyć, że pierwszy sposób może być jedynym sposobem. Ktoś ma lepsze pomysły?
**** Edit: Uwagi dodatkowe ****
Próba wywołania metody bezpośrednio, jak w poniższym programie z liniami odkomentowanymi, nie działa (błąd będzie „operacja może destabilizują środowisko wykonawcze "). Odkomentuj linie, a zobaczysz, że działa zgodnie z oczekiwaniami, zwracając "True".
var m = new DynamicMethod("M", typeof(bool), Type.EmptyTypes);
var il = m.GetILGenerator();
var ctor = typeof(Nullable<int>).GetConstructor(new[] { typeof(int) });
il.Emit(OpCodes.Ldc_I4_6);
il.Emit(OpCodes.Newobj, ctor);
//var local = il.DeclareLocal(typeof(Nullable<int>));
//il.Emit(OpCodes.Stloc, local);
//il.Emit(OpCodes.Ldloca, local);
var getValue = typeof(Nullable<int>).GetMethod("get_HasValue");
il.Emit(OpCodes.Call, getValue);
il.Emit(OpCodes.Ret);
Console.WriteLine(m.Invoke(null, null));
więc nie można po prostu wywołać metodę z wartością na stosie, ponieważ jest to typ wartości (choć może gdyby to był rodzaj odniesienia).
Co chciałbym osiągnąć (lub wiedzieć, czy jest to możliwe), to zastąpienie trzech linii, które są pokazane w komentarzach, ale należy zapewnić działanie programu, bez korzystania z tymczasowego lokalnego.
Tak to też działa idealnie, ale nadal wymaga miejscowy. Myślę, że to zaczyna potwierdzać moje pierwotne podejrzenie, że nie można tego zrobić bez lokalnego. myślę Stloc działa, ponieważ lokalna ma dodatkowe metadane typu są przechowywane ... ale potem znowu tak robi Zadzwoń ... dziwne. –
Tak, uważam za bardzo dziwne, że nie działa tak, jak się tego spodziewałem. Jeśli dynamiczna metoda bierze pustych jako argument, wszystko co musisz zrobić to zadzwonić ldarg_0, ale jestem zakładając, że rzeczywiście trzeba utworzyć typ wartości w metodzie. –
Rzeczywiście, muszę utworzyć wartości w ramach metody. Kłopot mam to, że istnieje spora liczba z nich za metodą (różnych rodzajów), co oznacza sporą liczbę mieszkańców wykorzystywanych wyłącznie do operacji przejściowych. To nie jest wielka sprawa i wszystko działa dobrze, ale wydaje się trochę nieporządna. –