c# 发出动态方法将 DateOnly 转换为 Datetime

c# Emit dynamic method to convert DateOnly To Datetime

提问人:ildanny 提问时间:10/10/2023 最后编辑:ildanny 更新时间:10/10/2023 访问量:51

问:

我正在学习 IL(中间语言),以便将 C# 应用程序应用到中。

使用 c#,我正在尝试生成一个动态方法来将 DateOnly 转换为 DateTime。 在 C# 中,它只是:

    public static DateTime ToDateTime(DateOnly dtOnly)
    {
        return dtOnly.ToDateTime(new TimeOnly(0));
    }

我的代码是:

using System.Reflection.Emit;

namespace ConsoleApp2
{
  public class MyModule
  {
    public static void CreateAndInvokeDynamicMethod()
    {
      var fuc = GenerateDateTimeFromDateOnly2();
      DateOnly dt = new DateOnly(1974, 1, 17);
      DateTime to = fuc.Invoke(dt);
      return;
    }

    public static Func<DateOnly, DateTime> GenerateDateTimeFromDateOnly2()
    {
      Type[] methodArgs = { typeof(int) };

      DynamicMethod methodBuilder = new DynamicMethod(
          "JustATest",
          typeof(DateTime),
          new Type[] { typeof(DateOnly) },
          typeof(MyModule).Module)
      ;

      ILGenerator ilGenerator = methodBuilder.GetILGenerator();

      // Load the DateOnly argument onto the stack
      ilGenerator.Emit(OpCodes.Ldarg_0);

      ilGenerator.Emit(OpCodes.Ldc_I4_0); // Load 0
      ilGenerator.Emit(OpCodes.Ldc_I4_0); // Load 0
      ilGenerator.Emit(OpCodes.Newobj, typeof(TimeOnly).GetConstructor(new Type[] { typeof(int), typeof(int) }));
      //Now, I have a TimeOnly in the Stack

      // Call the DateOnly.ToDateTime method
      ilGenerator.EmitCall(OpCodes.Call, typeof(DateOnly).GetMethod("ToDateTime", new Type[] { typeof(TimeOnly) }), null);
      ilGenerator.Emit(OpCodes.Ret);
      return (Func<DateOnly, DateTime>)methodBuilder.CreateDelegate(typeof(Func<DateOnly, DateTime>));
    }
  }
}

当我调用它时,我收到错误“试图读取或写入受保护的内存。这通常表明其他内存已损坏”

知道我的代码出了什么问题吗?

我还将 c# 反编译为 IL,但我没有看到任何相关差异。

.method public hidebysig 
    instance valuetype [System.Runtime]System.DateTime ToDateTime (
        valuetype [System.Runtime]System.DateOnly dtOn
    ) cil managed 
{
    // Method begins at RVA 0x206c
    // Code size 20 (0x14)
    .maxstack 3
    .locals init (
        [0] valuetype [System.Runtime]System.DateTime
    )

    IL_0000: nop
    IL_0001: ldarga.s dtOn
    IL_0003: ldc.i4.0
    IL_0004: ldc.i4.0
    IL_0005: newobj instance void [System.Runtime]System.TimeOnly::.ctor(int32, int32)
    IL_000a: call instance valuetype [System.Runtime]System.DateTime [System.Runtime]System.DateOnly::ToDateTime(valuetype [System.Runtime]System.TimeOnly)
    IL_000f: stloc.0
    IL_0010: br.s IL_0012

    IL_0012: ldloc.0
    IL_0013: ret
} // end of method GenericClass::ToDateTime

实际上,我不明白是否需要额外的 DateTime。 另外,无条件分支的目的是什么

    IL_000f: stloc.0
    IL_0010: br.s IL_0012
    IL_0012: ldloc.0
C# 中间语言

评论

1赞 Good Night Nerd Pride 10/10/2023
在不进行优化的情况下进行编译时,可能会生成一些额外的指令或临时变量,以便在调试时提供帮助。忽略这些或在发布模式下编译。nop
0赞 Good Night Nerd Pride 10/10/2023
您能否添加调用发出的方法?我想尝试重现您的问题,因为我也看不到您的说明中有任何错误。
2赞 nalka 10/10/2023
尝试而不是ilGenerator.Emit(OpCodes.Ldarga_S, 0);ilGenerator.Emit(OpCodes.Ldarg_0);
1赞 ildanny 10/10/2023
@nalka 非常感谢!它解决了问题!我现在看到反编译 c# 代码生成的代码使用“ldargA”
2赞 Marc Gravell 10/10/2023
如果差值丢失:ldarga 加载参数的地址;ldarg 加载参数的值 - 它们非常不同,当一个作为指针访问(即取消引用)时,它会在错误的位置查找

答: 暂无答案