【问题标题】:Why does var get resolved as a Double and not Long?为什么 var 被解析为 Double 而不是 Long?
【发布时间】:2012-02-14 12:29:33
【问题描述】:

在下面的代码中,我希望var 被解析为Int64,但它被解析为double。为什么会这样?

string a =  "1234";
bool asInt = true;
var b = (asInt) ? Int64.Parse(a) : Double.Parse(a) ;
Console.WriteLine(b.GetType());

【问题讨论】:

  • 我有点惊讶,甚至编译。我认为三元的双方都必须返回相同的类型,尽管我认为有一个从 long 到 double 的隐式对话
  • 有。 ,) 这解释了这一点。

标签: c# double int64


【解决方案1】:

存在从 Int64Double 的隐式转换,但不是其他方式(由于在该方向上可能会损失精度)。

由于条件的两个“分支”都需要解析为相同的类型,b 的类型最终被推断为Double

【讨论】:

  • 有道理。有什么方法可以在需要时创建 Int64 类型的变量 b 并在需要时创建 Double(基于 bool asInt)?当然,在 if 语句中初始化它是行不通的,因为它的范围被限制在 if 块内
  • @xbonez - 不使用条件运算符。必须在运行时推断/确定类型。您也许可以使用dynamic
  • 嗯...谢谢。我会研究动态的。我知道双打的数学运算速度较慢,所以我希望在不需要时不要使用双打。我会研究动态的,但如果这不起作用,我想我会接受它。
  • @xbonez:请注意,dynamic 有它自己的运行时开销。如果您想优化执行速度,最好使用double
  • @xbonez:使用动态可能会比两倍慢数十万倍。请记住,dynamic 在运行时再次启动编译器,这就是dynamic 的意思。如果您遇到整数和双精度算术之间的差异(几纳秒)相关的场景,那么您需要这样做非常仔细分析驱动分析。你不能只看代码就知道它的哪些部分需要一个机器周期和四个机器周期。
【解决方案2】:

您可以将long 隐式转换为double

您不能将 double 隐式转换为 long

因此,C# 编译器决定您的变量类型的唯一可能性是 double

Implicit Numeric Conversions Table

【讨论】:

    【解决方案3】:

    因为编译器需要推断出一个类型,该类型可以同时保存Int64.Parse(a)Double.Parse(a) 的值,而无需显式转换。如果推断出long,则表达式的其他部分将丢失精度。

    如果你需要区分类型,你必须声明两个变量并重写你的代码:

    if (asInt)
    {
        var b = Int64.Parse(a); // will infer a `long`
        Console.WriteLine(b.GetType());
    }
    else
    {
        var b = Double.Parse(a); // will infer a `double`
        Console.WriteLine(b.GetType());
    }
    

    【讨论】:

    • 那么,我有什么办法可以做你所做的,但又可以在 if-else 范围之外访问变量 b 吗?
    • @xbonez,是的,但是您应该将b 定义为object 类型:object b;
    • 完美……这就是我一直在寻找的东西。 Object 正是我需要的。谢谢!
    • 哦,等等...它不会让我对 Object (>、Int64 或 Double,这有点达不到目的,因为直到运行时我才知道类型。
    【解决方案4】:

    C# 编译器从三元的两个返回类型之间的公分母推断类型。 Int64 可以隐式转换为 Double。反之则不然。

    请注意,您的代码示例中的布尔值状态与推断的类型无关。

    【讨论】:

      【解决方案5】:

      这是?: 操作员的工作。它应该将所有结果转换为一种类型。

      附:你知道的+操作符的类似行为:

      string a =  "1234";
      var b = Int64.Parse(a) + Double.Parse(a) ;
      Console.WriteLine(b.GetType());
      

      附言要拥有你想要的,你应该使用object:

      string a =  "1234";
      bool asInt = true;
      object b;
      if(asInt) b=Int64.Parse(a); else b=Double.Parse(a);
      Console.WriteLine(b.GetType());
      

      P.P.P.S.另一种选择是:

              string a = "1234";
      #if asInt
              Int64 b = Int64.Parse(a);
      #else
              Double b = Double.Parse(a);
      #endif
              Console.WriteLine(b.GetType());
      

      定义 asInt 使用

      #define asInt
      

      【讨论】:

      • 不幸的是,object 要求我将其转换为Int64double,然后我才能对其进行任何操作,这是不可能的,因为我不知道类型直到运行时
      • 然后尝试条件编译指令,#if
      • 如果您不依赖算术运算符,您也可以使用泛型方法和/或类型。如果你是,那么你会做更多的把戏。
      【解决方案6】:

      我很惊讶没有人指出 如果你知道这个值是合法的 long 值,你可以通过显式转换来改变编译器的行为,然后使用 long.

      这可能有帮助,也可能没有帮助,具体取决于确定asInt 值的条件,以及您打算如何处理表达式的结果。这是一个例子:

      string a =  "1234.56"; 
      bool asDouble = a.Contains("."); 
      var b = asDouble ? (long)Double.Parse(a) : Int64.Parse(a);
      Console.WriteLine(b.GetType());
      

      事实上,在这个例子中,你不需要条件运算符;这也可以:

      string a =  "1234.56"; 
      var b = (long)Double.Parse(a);
      Console.WriteLine(b.GetType());
      

      换句话说,最好的解决方案可能不会使用三元运算符,但问题并没有提供足够的上下文来了解。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-10
        • 2021-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-22
        • 1970-01-01
        相关资源
        最近更新 更多