通过 .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.850000925362000
和44.8500009253620004
的位解释为Int64,您将获得4631508893792468976
和4631508893792468977
的值。
如您所见,第二个值是第一个加一的值。
因此,看起来有人在某处将双精度值解释为 Int64,然后将其递增 - 可能表明这是该行的新版本,因为您修改了它。
【讨论】:
数据集中的列是DataType System.Double
和 AutoIncrement False
- 甚至没有触及该列中的值(其他地方的整数列增加了)。因此,虽然我知道这有点不对劲,但我仍然无法弄清楚这是如何发生的或为什么会发生。以上是关于通过 .NET 远程传输后,双精度值发生了变化的主要内容,如果未能解决你的问题,请参考以下文章
如何在 .NET 中将双精度值转换为具有固定小数位数的小数类型值