Существует ли универсальный код CIL для преобразования экземпляра любого типа в строку?

Можно ли написать общие инструкции CIL, которые преобразуют экземпляры любого типа (как значения, так и ссылки) в System.String? В частности, меня интересует код Mono.Cecil, который вставляет эти инструкции в метод.

Анализируя общий метод, я придумал эти вызовы Mono.Cecil: (он должен преобразовать параметр i-го метода в строку)

System.Reflection.MethodInfo to_string_method_info = typeof( System.Object ).GetMethod( "ToString" );
Mono.Cecil.MethodReference to_string_reference = injectible_assembly.MainModule.Import( to_string_method_info );

Mono.Cecil.TypeReference argument_type = method_definition.Parameters[ i ].ParameterType;
method_definition.Body.Instructions.Add( processor.Create( Mono.Cecil.Cil.OpCodes.Constrained, argument_type ) );
method_definition.Body.Instructions.Add( processor.Create( Mono.Cecil.Cil.OpCodes.Callvirt, to_string_reference ) );

Однако при отладке я получаю исключение из внедренного метода, что "JIT-компилятор обнаружил внутреннее ограничение".

1 ответ

Решение

Редактировать:

Также важно отметить, что я использую typeof(object).GetMethod(...)не typeof(T).GetMethod(...) - ваша линия argument_type.GetType().GetMethod( "ToString" ); выглядит очень подозрительно ИМО.


Я подозреваю, что проблема в том, что вы загружаете локальный / аргумент, а не адрес локального / аргумента - в строке непосредственно перед тем, что показано. Constrained необходимо, чтобы он мог правильно выполнять реализацию статического вызова; для реализации виртуального вызова он может просто разыменовать это, чтобы получить фактическую ссылку.

Кроме этого: Constrained должно работать нормально - см. ниже (в частности, обратите внимание на Ldarga_S). Конечно, другой вариант заключается в использовании Box, но это будет иметь больше накладных расходов. Constrained это идеальный способ звонить ToString на произвольный тип.

using System;
using System.Reflection.Emit;

public class RefTypeNoImpl { }
public class RefTypeImpl { public override string ToString() { return "foo"; } }
public struct ValTypeNoImpl { }
public struct ValTypeImpl { public override string ToString() { return "bar"; } }

static class Program
{
    static void Main()
    {
        Test<RefTypeNoImpl>();
        Test<RefTypeImpl>();
        Test<ValTypeNoImpl>();
        Test<ValTypeImpl>();
    }


    static void Test<T>() where T : new()
    {
        var dm = new DynamicMethod("foo", typeof(string), new[] { typeof(T) });
        var il = dm.GetILGenerator();
        il.Emit(OpCodes.Ldarga_S, 0);
        il.Emit(OpCodes.Constrained, typeof(T));
        il.Emit(OpCodes.Callvirt, typeof(object).GetMethod("ToString"));
        il.Emit(OpCodes.Ret);
        var method = (Func<T, string>)dm.CreateDelegate(typeof(Func<T, string>));
        Console.WriteLine(method(new T()));
    }
}
Другие вопросы по тегам