- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
概述(请原谅我说得这么详细,但我宁愿它太多也不愿太少):我正在尝试为我们的解决方案编辑 Dapper 源代码,以便在读取任何 DateTime 或 Nullable 时从数据库中,它的 DateTime.Kind 属性始终设置为 DateTimeKind.Utc。
在我们的系统中,保证来自前端的所有 DateTimes 都是 UTC 时间,并且数据库 (Sql Server Azure) 将它们存储为 UTC 中的 DateTime 类型(我们没有使用 DateTimeOffsets,我们只是一直在制作在将日期时间存储在数据库中之前确保日期时间是 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,而不是 DateTime?)但这也失败了。
有人可以告诉我我缺少什么吗?
最佳答案
如有疑问,请编写一个执行相同操作的最小 C# 库,然后查看编译后的结果:
你的尝试似乎等同于
using System;
static class Program {
public static DateTime? SetUtc(object value) {
return new DateTime?(DateTime.SpecifyKind(((DateTime?)value).Value, DateTimeKind.Utc));
}
};
这编译为:
$ mcs test.cs -target:library -optimize+ && monodis test.dll... IL_0000: ldarg.0 IL_0001: unbox.any valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime> IL_0006: stloc.0 IL_0007: ldloca.s 0 IL_0009: call instance !0 valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>::get_Value() IL_000e: ldc.i4.1 IL_000f: call valuetype [mscorlib]System.DateTime valuetype [mscorlib]System.DateTime::SpecifyKind(valuetype [mscorlib]System.DateTime, valuetype [mscorlib]System.DateTimeKind) IL_0014: newobj instance void valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>::'.ctor'(!0) IL_0019: ret ...
Thee first difference with your version is that ldarg
is used instead of ldarga
. You want unbox.any
to check the passed value, not a pointer to the passed value. (ldarga
does work too in my tests, but ldarg
makes more sense anyway.)
The second, and more relevant, difference with your version is that after unbox.any
, the value is stored, and then a reference to that location is loaded. This is because the implicit this
parameter of instance methods of value types have type ref T
, rather than the T
you're used to for instance methods of reference types. If I do include that stloc.0
/ldloca.s 0
, your code then passes its test, on my system.
However, as you unconditionally read the Value
property after casting to DateTime?
, you might as well cast straight to DateTime
and avoid the problem entirely. The only difference would be which exception you get when a value of the wrong type is passed in.
If you instead want something like
public static DateTime? SetUtc(object value) {
var local = value as DateTime?;
return local == null ? default(DateTime?) : DateTime.SpecifyKind(local.Value, DateTimeKind.Utc);
}
然后我会用类似的东西
var label1 = il.DefineLabel();
var label2 = il.DefineLabel();
il.Emit(OpCodes.Ldarg_S, 0); // object
il.Emit(OpCodes.Isinst, typeof(DateTime)); // boxed DateTime
il.Emit(OpCodes.Dup); // boxed DateTime, boxed DateTime
il.Emit(OpCodes.Brfalse_S, label1); // boxed DateTime
il.Emit(OpCodes.Unbox_Any, typeof(DateTime)); // unboxed DateTime
il.Emit(OpCodes.Ldc_I4_1); // unboxed DateTime, int
il.Emit(OpCodes.Call, typeof(DateTime).GetMethod("SpecifyKind")); // unboxed DateTime
il.Emit(OpCodes.Newobj, typeof(DateTime?).GetConstructor(new[] { typeof(DateTime) })); // unboxed DateTime?
il.Emit(OpCodes.Br_S, label2);
il.MarkLabel(label1); // boxed DateTime (known to be null)
il.Emit(OpCodes.Unbox_Any, typeof(DateTime?)); // unboxed DateTime?
il.MarkLabel(label2); // unboxed DateTime?
il.Emit(OpCodes.Ret);
关于c# - 为方法发出代码时取消装箱可为 Nullable 使评估堆栈处于意外(对我而言)状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21711255/
我有一个发出值的 Observable 源 source1,如果它没有发出任何东西超过 2 秒,我想切换到后备源 source2。如果 source1 再次发射,我想从中发射。依此类推,无限期。 到目
我正在使用 postfix 发送电子邮件。当我将电子邮件发送到其他域时它工作正常,但是当我将电子邮件发送到配置后修复的同一个域时它不发送电子邮件。 下面是我的配置: myhostname = [FQD
我最近将 ipython 和 pandas 更新为最新的稳定版本。它导致 matplotlib 中出现了一些奇怪的行为,如果我从终端运行(以前的行为)脚本,我将无法显示数字。如果我在 ipython
我的应用程序是一个网络应用程序。它的工作是接收我想将它们作为信号发出的数据包流(QByteArray)。这样做会不会效率低下?我关心复制大缓冲区。 最佳答案 QByteArray 使用 Copy-on
有 QTableWidget。我需要发送带有行列和文本的 cellChanged 信号。我怎样才能做到这一点? —— 我已经用插槽连接了信号。我需要发送 信号。 最佳答案 您必须使用 connect
我编写了一个简单的玩具语言编译器前端,它使用 llvm-sys 生成 LLVM IR (LLVM 的 C library 的 Rust 绑定(bind))。然后我通过创建 LLVMTargetMach
我想知道如何像那里描述的那样发出 HTTP POST 请求 http://code.google.com/apis/documents/docs/3.0/developers_guide_protoc
简单的问题。我需要在 GWT 中发出一个重定向到新页面的 GET 请求,但我找不到正确的 API。 有吗?我应该自己简单地形成 URL 然后做 Window.Location.replace ? (原
我正在使用 paging3我有两个不同的寻呼源。问题是Coroutine Scope只发出第一个寻呼流 在 ViewModel我有两个分页流程 val pagingFlow1 = Pager(Pagi
docker doc 中没有任何解释,也没有 docker 中看似任何内置变量来查找构建图像的原始工作目录。 我想在不同的目录上运行命令,并在某个时候回到我启动 docker build 的位置。 我
我试图使一个puppeteer.js机器人能够暂停并恢复其工作。 总的来说,我有一个带有十几个异步方法的类,事件发射器和一个名为“state”的属性,该属性使用setter进行更改。当我发生事件“停止
这个问题已经有答案了: Is it possible to send custom headers with an XHR ("Ajax" request)? (1 个回答) 已关闭 4 年前。 我想
如果浏览器打开与远程服务器的连接,是否可以通过 Javascript 访问同一连接? 我的网络上有一个小型以太网模块,我的编程有点像这样(伪代码): private var socket while(
尝试发出 HTTP 请求时,出现错误: {-# LANGUAGE OverloadedStrings #-} import Network.HTTP.Conduit -- the main modul
我有这个异步任务: public class likeTheJoke extends AsyncTask{ @Override protected Void doInBa
当进程终止并为其发出 wait() 时会发生什么?当一个子进程终止但没有人为其执行 wait() 时会发生什么?如果对尚未终止的进程执行 wait() 会发生什么情况? 最佳答案 如果我误解了这些问题
我尝试使用以下小部件结构、信号连接和回调将与 GtkTextView 支持的击键相关的信号(CTRL+a、CTRL+x 等)附加到工具栏按钮: typedef struct { GtkWidg
我有以下 base64 编码的字符串,我需要使用 Swift 对它进行 base64 解码: KimHser2RvFf9RPjajWO4K/odT51hTlISwMKNIfPUC+gXYZKNjGDC
我正在使用 Facebook Messenger webview 显示表单,在提交时,我想将消息发送回用户并关闭 webview。我现在的问题是 webview/浏览器没有发送消息就关闭了。我不知道这
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我是一名优秀的程序员,十分优秀!