通过 .NET 远程传输后,双精度值发生了变化

Posted

技术标签:

【中文标题】通过 .NET 远程传输后,双精度值发生了变化【英文标题】:Double value changed after transmitting it via .NET remoting 【发布时间】:2015-07-09 00:32:57 【问题描述】:

我有一个应用程序将 ADO.NET 数据集和数据适配器与远程处理(客户端/服务器架构,通过远程处理传输数据集)结合使用。

我现在面临以下问题:

TL;DR:通过远程将数据集发送到服务器后,双值 44.850000925362000 变为 44.850000925362004

我通过保存数据集在数据库中创建了一个新行,其中包含一个浮点列(在数据集中映射为双精度)。保存的double值是44.850000925362

然后我从数据库中读取这一行 (DataAdapter.Fill) 并获得相同的值(使用 BitConverter.DoubleToInt64 检查)。此数据集通过远程处理传递到客户端,然后合并到客户端上的用例数据集中。仍然保持相同的值。

这个数据集然后被合并到一个用例数据集中,其中的行被导入到另一个表中(因为从视图中读取,保存到表中)并且在传输用例数据集之前更改了一个值(现在包含一个另一个表中的行)。

在客户端,该值仍然相同 - 但一旦数据集到达服务器,相关值就会不同(尽管没有对特定列进行任何更改 - 它仍然是 Unchanged 甚至原始值不同)。

示例: 保存44.850000925362000 阅读44.850000925362000 合并、导入、修改行 - 仍然是 44.850000925362000 发送到服务器保存,服务器上是44.850000925362004

...然后导致ConcurrencyException,因为记录是使用44.850000925362000 保存的 - 但数据适配器更新在WHERE 条件中使用44.850000925362004(乐观并发)。

中间没有其他人碰过那一行。

更新

我尝试设置一个测试服务器,那里一切正常。有趣的是:如果我在不同的服务中使用相同的程序集,它可以正常工作。我在配置或启动中找不到任何可以解释这一点的东西。 我在两者上都使用了二进制格式化程序,两者都是 .NET 4.0,都使用相同的源代码......但一个的行为与另一个不同。

进一步更新

我什至捕获了为更新执行的 SQL 语句。如果我在SELECT 语句中将参数作为WHERE 子句运行,它将获取正确的记录。因此,当我手动执行此操作(通过 SQL Management Studio)时,它接受行中的值与我为条件提供的值之间的一个小增量。 不过,通过适配器运行更新时,它根本不起作用。

不管怎样,我已经放弃了。我已经将它四舍五入到 5 位数字 - 无论如何比我在那个用例中需要的精度要高得多。如果数字变大,可能会产生奇怪的结果,但我不希望在那个用例中出现这种情况(我们谈论的是重量,以千克为单位)。

【问题讨论】:

尝试直接在数据集之外发送一个双精度。这表明问题是否与 DataSet 有任何关系。然后尝试使用 BinaryFormatter 序列化 DataSet。这表明问题是否与远程处理有关。 Remoting 是一项遗留技术,保留它是为了与现有应用程序向后兼容,不建议用于新开发。现在应该使用 WCF 或 ASP.NET Web API 开发分布式应用程序。请参阅msdn.microsoft.com/en-us/library/vstudio/xws7132e.aspx 顶部的注释以获取证据。 我从未说过它是一个新应用程序;)我将尝试通过将普通的 double 作为参数传递给远程服务器来重现它,并且还将尝试将其包装在 MarshalByValue 对象中的变体(例如数据集是)。 【参考方案1】:

我可以告诉你这里发生了什么。不过我不知道为什么:

如果您将44.85000092536200044.8500009253620004 的位解释为Int64,您将获得46315088937924689764631508893792468977 的值。

如您所见,第二个值是第一个加一的值。

因此,看起来有人在某处将双精度值解释为 Int64,然后将其递增 - 可能表明这是该行的新版本,因为您修改了它。

【讨论】:

数据集中的列是 DataType System.DoubleAutoIncrement False - 甚至没有触及该列中的值(其他地方的整数列增加了)。因此,虽然我知道这有点不对劲,但我仍然无法弄清楚这是如何发生的或为什么会发生。

以上是关于通过 .NET 远程传输后,双精度值发生了变化的主要内容,如果未能解决你的问题,请参考以下文章

如何处理 vb.net 中双精度数的舍入错误?

如何在 .NET 中将双精度值转换为具有固定小数位数的小数类型值

Java - Decimal Format.parse 返回具有指定小数位数的双精度值

单精度小数点后面有几位?

获取双精度值的小数位

SCP远程传输文件