【问题标题】:Is there a generic CIL code to convert any type instance to string?是否有通用 CIL 代码将任何类型实例转换为字符串?
【发布时间】:2013-08-13 12:21:03
【问题描述】:

是否可以编写将任何类型(值和引用)的实例转换为 System.String 的通用 CIL 指令? 特别是,我对将这些指令注入方法的 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 编译器遇到内部限制”。

【问题讨论】:

  • 在这种情况下,PEVerify 非常有用,因为它可以告诉您代码有哪些具体错误。

标签: .net cil il mono.cecil


【解决方案1】:

编辑:

同样重要的是:请注意,我使用的是 typeof(object).GetMethod(...),而不是 typeof(T).GetMethod(...) - 你的行 argument_type.GetType().GetMethod( "ToString" ); 看起来很可疑 IMO。


我怀疑问题在于您正在加载本地/参数,而不是本地/参数的 地址 - 在显示的 行之前。 Constrained 需要这个才能正确执行静态调用实现;对于虚拟调用实现,它可以简单地取消引用 this 以获取 实际 引用。

除此之外: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()));
    }
}

【讨论】:

  • 这正是我所做的:Ldarg 而不是 Ldarga。
  • @zagrobelski 不错的猜测;p
猜你喜欢
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
  • 1970-01-01
  • 2017-10-09
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多