概述(请原谅我如此详细,但我宁愿它太多也不愿太少):我正在尝试编辑我们解决方案的 Dapper 源,这样当从数据库中读取任何 DateTime 或 Nullable 时,其 DateTime.Kind 属性始终设置为 DateTimeKind.Utc。
在我们的系统中,所有来自前端的 DateTime 都保证为 UTC 时间,并且数据库(Sql Server Azure)将它们存储为 UTC 中的 DateTime 类型(我们不使用 DateTimeOffsets,我们只是始终确保 DateTime在将其存储在数据库中之前是 UTC。)
我一直在阅读有关如何使用 ILGenerator.Emit(...) 为 DynamicMethods 生成代码的所有内容,并且觉得我对它如何与评估堆栈、本地人等一起工作有一个不错的理解。在我努力解决这个问题的过程中问题,我已经编写了一些代码示例来帮助我达到最终目标。我写了一个 DynamicMethod 以一个 DateTime 作为参数,调用 DateTime.SpecifyKind,返回值。那么DateTime也一样吗?类型,使用其 Nullable.Value 属性获取 SpecifyKind 方法的 DateTime。
这就是我的问题所在:在 dapper 中,DateTime(或 DateTime?我实际上并不知道,但是当我将它视为要么我没有得到我期望的结果时)被装箱了。因此,当我尝试使用 OpCodes.Unbox 或 OpCodes.Unbox_Any,然后将结果视为 DateTime 或 DateTime?时,我会收到 VerificationException:操作可能会破坏运行时的稳定性。
显然我错过了一些关于拳击的重要内容,但我会给你我的代码示例,也许你可以帮助我让它工作。
这有效:
[Test]
public void Reflection_Emit_Test3()
{
//Setup
var dm = new DynamicMethod("SetUtc", typeof(DateTime?), new Type[] {typeof(DateTime?)});
var nullableType = typeof(DateTime?);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarga_S, 0); // [DateTime?]
il.Emit(OpCodes.Call, nullableType.GetProperty("Value").GetGetMethod()); // [DateTime]
il.Emit(OpCodes.Ldc_I4, (int)DateTimeKind.Utc); // [DateTime][Utc]
il.Emit(OpCodes.Call, typeof(DateTime).GetMethod("SpecifyKind")); //[DateTime]
il.Emit(OpCodes.Newobj, nullableType.GetConstructor(new[] {typeof (DateTime)})); //[DateTime?]
il.Emit(OpCodes.Ret);
var meth = (Func<DateTime?, DateTime?>)dm.CreateDelegate(typeof(Func<DateTime?, DateTime?>));
DateTime? now = DateTime.Now;
Assert.That(now.Value.Kind, Is.Not.EqualTo(DateTimeKind.Utc));
//Act
var nowUtc = meth(now);
//Verify
Assert.That(nowUtc.Value.Kind, Is.EqualTo(DateTimeKind.Utc));
}
我在这里得到了我的期望。耶!但这还没有结束,因为我们要处理拆箱...
[Test]
public void Reflection_Emit_Test4()
{
//Setup
var dm = new DynamicMethod("SetUtc", typeof(DateTime?), new Type[] { typeof(object) });
var nullableType = typeof(DateTime?);
var il = dm.GetILGenerator();
il.DeclareLocal(typeof (DateTime?));
il.Emit(OpCodes.Ldarga_S, 0); // [object]
il.Emit(OpCodes.Unbox_Any, typeof(DateTime?)); // [DateTime?]
il.Emit(OpCodes.Call, nullableType.GetProperty("Value").GetGetMethod()); // [DateTime]
il.Emit(OpCodes.Ldc_I4, (int)DateTimeKind.Utc); // [DateTime][Utc]
il.Emit(OpCodes.Call, typeof(DateTime).GetMethod("SpecifyKind")); //[DateTime]
il.Emit(OpCodes.Newobj, nullableType.GetConstructor(new[] { typeof(DateTime) })); //[DateTime?]
il.Emit(OpCodes.Ret);
var meth = (Func<object, DateTime?>)dm.CreateDelegate(typeof(Func<object, DateTime?>));
object now = new DateTime?(DateTime.Now);
Assert.That(((DateTime?) now).Value.Kind, Is.Not.EqualTo(DateTimeKind.Utc));
//Act
var nowUtc = meth(now);
//Verify
Assert.That(nowUtc.Value.Kind, Is.EqualTo(DateTimeKind.Utc));
}
这只是直接不会运行。我得到了 VerificationException,然后我在角落里哭了一会儿,直到我准备好再试一次。
我尝试过期待 DateTime 而不是 DateTime?(拆箱后,假设 DateTime 在 eval 堆栈上,而不是 DateTime?)但这也失败了。
有人可以告诉我我错过了什么吗?