【问题标题】:Addition in C#.net doesn't work in some cases [duplicate]在某些情况下,C#.net 中的添加不起作用 [重复]
【发布时间】:2019-02-28 07:22:40
【问题描述】:

我有以下情况

beleg.PreisDB = (double?)orders.Where(x => x.orderId == beleg.auftrnr).Sum(x => x.itemPrice + x.shippingPrice + x.giftWrapPrice) ?? 0;
beleg.PreisCouponDB = (double?)orders.Where(x => x.orderId == beleg.auftrnr).Sum(x => x.itemPromotionDiscount + x.shipPromotionDiscount) ?? 0;
var gesamtPreis = Math.Round(beleg.PreisDB??0 + beleg.PreisCouponDB??0, 2);

在我的案例中,我在某些字段的调试中添加了一个快速监视:

beleg.PreisDB == 8.39
beleg.PreisDB??0 == 8.39
beleg.PreisCouponDB == -0.49
beleg.PreisCouponDB??0 == -0.49

现在奇怪的行为也来自快速观察,当然还有结果

beleg.PreisDB??0 + beleg.PreisCouponDB??0 == 8.39
Math.Round(beleg.PreisDB??0 + beleg.PreisCouponDB??0, 2) == 8.39
gesamtPreis == 8.39

所以加上 8.39 + -0.49 不是 7.9 而是 8.39 该代码在至少两个上运行了 60 万个案例,我有这种行为,其他人表现良好。我现在看不到我的错误。问题是.net 为什么会这样?我正在使用带有 .net 4.5.2 的 Visual Studio 2015。

【问题讨论】:

  • 您是否在调试器外部看到了这个?我已经看到调试器无法按预期工作的许多问题,但如果您可以在 minimal reproducible example 中显示此问题而不使用调试器,那将更加出乎意料并且更容易为您提供帮助。
  • 说了这么多,我想我也许能看出哪里出了问题——我需要检查一下……
  • 我已将问题作为重复项关闭;有关?? 的优先级可能令人惊讶的其他方式,请参阅stackoverflow.com/questions/3218140
  • 你这里的逻辑和“1+234+15是一样的,所以1 + 2 * 4 + 115。既然我得到了答案10,乘法必须被打破。不,在组合运算时必须在运算周围加上括号(1+2)*(4+1) 是 15。

标签: c# .net


【解决方案1】:

问题在于优先级 - + 的优先级高于 ??,因此它“绑定得更紧密”。

这里有一个完整的例子来演示:

using System;

class Test
{
    static void Main()
    {
        double? x = 8.39;
        double? y = -0.49;

        // Your expression
        Console.WriteLine(x ?? 0 + y ?? 0);

        // The equivalent you're expecting
        Console.WriteLine((x ?? 0) + (y ?? 0));

        // The actual bracketing
        Console.WriteLine(x ?? ((0 + y) ?? 0));
    }
}

另一种选择是使用Nullable<T>.GetValueOrDefault() 而不是?? 0

Console.WriteLine(x.GetValueOrDefault() + y.GetValueOrDefault());

但我想我可能只使用带括号的版本 - 所以在你的情况下:

var gesamtPreis = Math.Round((beleg.PreisDB ?? 0) + (beleg.PreisCouponDB ?? 0), 2);

我肯定会像大多数其他运算符一样将空格放在?? 周围,否则它会给您印象绑定非常紧密(就像. 运算符一样)。

【讨论】:

  • 显然Coverity删除了我在2013年写的关于这个问题的文章。烦!我会看看能不能把它从路边机里拿出来重新发布。
  • 你能解释一下为什么实际的包围是x??(0+(y??0))而不是x??((0+y)??0)吗?
  • @EricLippert:嗯,我可以解释为什么我它是x??(0+(y??0)) - 我不够小心:) 现在修复了。我想。但也许不是——我还需要检查关联性。
  • @EricLippert:是的。现在的答案与您之前的评论相同。我想我需要再来一杯咖啡。
  • 当然?? 运算符要求它的左侧可以为空,因此1??whatever 不是合法代码。但更大的一点很重要。 ?? 运算符被定义为无条件地评估其左操作数并有条件地评估其右操作数。
【解决方案2】:
var gesamtPreis = Math.Round(beleg.PreisDB??0 + beleg.PreisCouponDB??0, 2);
// Executed in this order
var gesamtPreis = Math.Round(beleg.PreisDB ?? ((0 + beleg.PreisCouponDB) ?? 0))

您的代码以不同的顺序执行。因为beleg.PreisDB 不是null,所以永远不会添加beleg.PreisCouponDB。尝试添加一些括号:

// Executed as you want it to be
var gesamtPreis = Math.Round((beleg.PreisDB ?? 0) + (beleg.PreisCouponDB ?? 0), 2);

【讨论】:

    猜你喜欢
    • 2018-11-28
    • 2011-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-17
    • 2017-06-29
    • 1970-01-01
    相关资源
    最近更新 更多