Dapper:这两段代码有什么区别?

Dapper: What's the difference between these two pieces of code?

我已经为 Dapper 注册了一个自定义类型处理程序来 Json 序列化一个字符串。这按预期工作。然而,在编码时,我发现重构后有两段代码,后一段没有触发数据类型处理程序,但我认为应该有,所以有什么区别?

首先是按预期工作的代码 - 自定义类型处理程序由 dapper 调用,数据在插入 table:

时被序列化
if (val.GetType() != typeof (String))
{
    var v = new JsonString {Value = val};
    this.Connection.Execute("insert into misc (k,v) values (@keyName, @v)", 
        new { keyName, v });
}
else
{
    this.Connection.Execute("insert into misc (k,v) values (@keyName, @val)", 
        new { keyName, val });
}

现在,代码无法正常工作,因为它插入 table 完全限定类型字符串而不是序列化数据,但我认为它在语义上相似:

var v = val.GetType() != typeof (String)
        ? new JsonString {Value = val}
        : val;

// t is set to type of JsonString, therefore the dapper type handler should be used
var t = v.GetType();

this.Connection.Execute("insert into misc (k,v) values (@keyName, @v)", 
    new { keyName, v });

这是一个小巧的 bug 还是 c# 的怪癖?我认为这与三元条件中的自动输入有关,这是失败点,但 t 设置为由 Dapper(或自定义类型处理程序)序列化的数据类型。有什么不同?

假设 JsonString 和 String 之间没有可用的隐式转换,第二个示例中的代码将不起作用。如果有可用的隐式转换,您需要提供有关正在发生的异常的更多信息。

在 JsonString 之间没有可用的转换,用 var 类型声明的变量具有由编译器推断的类型 ((https://msdn.microsoft.com/en-us/library/bb384061.aspx)。在这种情况下,变量 v 是 JsonString 类型或 String 类型,具体取决于分配的哪一部分发生。如果编译器假定它是 JsonString 类型,则任何带有 String 的分配都将失败。

在您的第二个代码示例中,第一行代码是错误的,因为赋值导致两种不同的数据类型被赋值给变量 v。

我假设 val 的编译时类型(即声明类型)是 System.Object。我将解释为什么这两种情况不等同。

必须小心区分变量的编译时类型和实际的 运行 时类型(由 .GetType() 找到)。

在第一段代码中,在 运行 时 val 不是 String 的分支中,我们声明:

var v = new JsonString {Value = val};

此处 varJsonString 替代,因为这是 = 赋值右侧的编译时类型。然后是匿名类型实例:

new { keyName, v }

将成为class(我将其称为class Anonymous1)与成员

public JsonString v { get { ... } }

现在,在第二段代码中,我们改为:

var v = val.GetType() != typeof (String)
        ? new JsonString {Value = val}
        : val;

三元运算符的操作数的编译时类型是:

{bool} ? {JsonString} : {object}

在编译时,必须找到 JsonStringobject 的最佳通用类型。该常见类型是 object。所以 object 在这里成为 v 的编译时类型,即 var 在这里表示 object

然后是匿名类型:

new { keyName, v }

是一种类型“Anonumous2”,其“第二个”属性 为:

public object v { get { ... } }

所以总结一下:在第一种情况下,你传入一个对象,它有一个 属性 v 声明为 JsonString ,当检索 returns 一个 JsonSting 恰好有 运行 次 JsonString。在第二个代码示例中,您传入一个对象,该对象具有声明为 object 的 属性 v,在检索时 returns 恰好具有 运行-时间类型JsonString.

我不太了解Dapper的工作原理!但大概当它看到(通过反射?) 属性 类型是 object 时,它只是简单地调用 .ToString() 。如果 object 碰巧是 运行 时间类型 string,那应该没问题,因为 string.ToString() 被覆盖了。但是JsonString.ToString()不是那样的

当 Dapper 看到 属性 被声明为 JsonString 时,Dapper 会做一些比调用 .ToString().

更聪明的事情