Динамический метод C #: возвращает строковое представление целого числа - PullRequest
0 голосов
/ 11 октября 2018

Я хочу создать динамический метод, который принимает параметр Int32 и возвращает его строковое представление:

public class Item
{
    public int Age { get; } = 22;
}

static void CreateDynamicMethod()
{
    var ageGet = typeof(Item).GetProperty("Age").GetGetMethod(true);
    var intToString = typeof(int).GetMethod("ToString", new Type[] { });

    var dm = new DynamicMethod("getAgeString", typeof(string), new[] { typeof(Item) }, typeof(Item).Module);
    var il = dm.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0); //load Item instance on stack
    il.Emit(OpCodes.Callvirt, ageGet); //age 44 on stack
    il.Emit(OpCodes.Call, intToString); //call tostring for age, "44" on stack now
    il.Emit(OpCodes.Ret); //return "44"
    var agestr = (Func<Item, string>)dm.CreateDelegate(typeof(Func<Item, string>));
    Console.WriteLine(agestr.Invoke(new Item()));
}

Но метод завершается ошибкой с исключением Object reference not set to an instance of an object.Что я пропустил?

ОБНОВЛЕНИЕ : Я проверил MSIL версии C # моего метода:

static string GetAge(Item item)
{
    return item.Age.ToString();
}

И я обнаружил, что мне нужно получить целое число изстек перед вызовом intToString.Полная версия:

var dm = new DynamicMethod("getAgeString", typeof(string), new[] { typeof(Item) }, typeof(Item).Module);
var il = dm.GetILGenerator();
il.DeclareLocal(typeof(int)); //[NEW] declare local integer variable
il.Emit(OpCodes.Ldarg_0); //load Item instance on stack
il.Emit(OpCodes.Callvirt, ageGet); //age 44 on stack now
il.Emit(OpCodes.Stloc_0); //[NEW] pop ineteger from stack to local variable
il.Emit(OpCodes.Ldloca_S, 0); //[NEW] load address of integer variable onto stack
il.Emit(OpCodes.Call, intToString); //call tostring for age, "44" on stack now
il.Emit(OpCodes.Ret); //return "44"
var agestr = (Func<Item, string>)dm.CreateDelegate(typeof(Func<Item, string>));
Console.WriteLine(agestr.Invoke(new Item()));

и теперь работает.

1 Ответ

0 голосов
/ 11 октября 2018

Я не профессионал по IL, но я думаю, что вам нужно указать int для вызова ToString.Я предполагаю, что целочисленное значение 22 обрабатывается JIT как указатель на объект.Затем среда выполнения преобразует нарушение доступа в NRE, что и для небольших значений указателя.

Я бы порекомендовал полностью отбросить отражение и использовать деревья выражений.Гораздо проще, та же производительность.

...