动态生成的 MSIL 中奇怪的 DateTime ToString 行为
Weird DateTime ToString behavior in Dynamically generated MSIL
我需要在 运行 时动态构建 属性 检索方法并快速执行,因此我使用 Reflection Emit
:
开发了一个解决方案
public static void Func(string properyName, A obj)
{
var type = obj.GetType();
var dynamicMethod = new DynamicMethod("PropertyExtractor", typeof(string), new[] { typeof(A) }, type, true);
var ilGen = dynamicMethod.GetILGenerator();
var getMethod = type.GetMethod($"get_{properyName}");
var property = type.GetProperty(properyName);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Castclass, type);
ilGen.Emit(OpCodes.Callvirt, getMethod);
var toStringMethod = property.PropertyType.GetMethod("ToString", Type.EmptyTypes);
ilGen.Emit(OpCodes.Call, toStringMethod);
ilGen.Emit(OpCodes.Ret);
var @delegate = (F)dynamicMethod.CreateDelegate(typeof(F));
var a = @delegate(obj);
}
public delegate string F(A obj);
public abstract class A
{
public int Id { get; set; }
public string Name { get; set; }
}
public class B : A
{
public DateTime Timestamp { get; set; }
}
这是调用它的代码:
var obj = new B
{
Id = 1,
Name = "SomeName",
Timestamp = DateTime.Today
};
Func("Timestamp", obj);
这只是为了测试,这就是为什么它位于名为 Func
且参数类型为 A
的方法中,等等。
如您所见,您为它指定了 属性 的名称和实例,它会创建一个委托来检索该特定实例中 属性 的字符串值。一切正常,直到 DateTime
。我使用分配给 属性 的 DateTime.Now
进行测试,每次我 运行 函数时,我都会得到奇怪的值,例如:
我试着放一个 IFormatProvider 以防万一 - 结果相同。
.NET 版本为 4.7.1,
提前致谢。
我发现了问题。 DateTime 是一种值类型,而 ToString 需要将地址加载到计算堆栈,而不是值。当我添加了一个局部变量的时候,并添加了将值存储在局部变量中的指令,然后加载该变量的地址,它就解决了。感谢所有回复的人。
我需要在 运行 时动态构建 属性 检索方法并快速执行,因此我使用 Reflection Emit
:
public static void Func(string properyName, A obj)
{
var type = obj.GetType();
var dynamicMethod = new DynamicMethod("PropertyExtractor", typeof(string), new[] { typeof(A) }, type, true);
var ilGen = dynamicMethod.GetILGenerator();
var getMethod = type.GetMethod($"get_{properyName}");
var property = type.GetProperty(properyName);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Castclass, type);
ilGen.Emit(OpCodes.Callvirt, getMethod);
var toStringMethod = property.PropertyType.GetMethod("ToString", Type.EmptyTypes);
ilGen.Emit(OpCodes.Call, toStringMethod);
ilGen.Emit(OpCodes.Ret);
var @delegate = (F)dynamicMethod.CreateDelegate(typeof(F));
var a = @delegate(obj);
}
public delegate string F(A obj);
public abstract class A
{
public int Id { get; set; }
public string Name { get; set; }
}
public class B : A
{
public DateTime Timestamp { get; set; }
}
这是调用它的代码:
var obj = new B
{
Id = 1,
Name = "SomeName",
Timestamp = DateTime.Today
};
Func("Timestamp", obj);
这只是为了测试,这就是为什么它位于名为 Func
且参数类型为 A
的方法中,等等。
如您所见,您为它指定了 属性 的名称和实例,它会创建一个委托来检索该特定实例中 属性 的字符串值。一切正常,直到 DateTime
。我使用分配给 属性 的 DateTime.Now
进行测试,每次我 运行 函数时,我都会得到奇怪的值,例如:
我发现了问题。 DateTime 是一种值类型,而 ToString 需要将地址加载到计算堆栈,而不是值。当我添加了一个局部变量的时候,并添加了将值存储在局部变量中的指令,然后加载该变量的地址,它就解决了。感谢所有回复的人。