【问题标题】:Operator ">" cannot be applied to type 'ulong' and 'int'运算符 ">" 不能应用于类型 'ulong' 和 'int'
【发布时间】:2012-06-18 15:44:28
【问题描述】:

我很想知道为什么 C# 编译器只给我第二个 if 语句的错误消息。

enum Permissions : ulong
{
    ViewListItems = 1L,
}

public void Method()
{
    int mask = 138612833;
    int compare = 32;

    if (mask > 0 & (ulong)Permissions.ViewListItems > 32)
    {
        //Works
    }

    if (mask > 0 & (ulong)Permissions.ViewListItems > compare)
    {
        //Operator '>' cannot be applied to operands of type 'ulong' and 'int'
    }
}

【问题讨论】:

  • 这个错误的原因很清楚。在第二个示例中,您尝试使用整数执行非法操作。在第一个示例中,32 被视为ulong。您实际上应该将mask 设为ulong
  • @Ramhound 要么(使compare 成为ulong),要么使compare 成为const 变量,所以const int compare = 32;。如果常量表达式为非负数,它们会很高兴地在编译时自动从 int 转换为 ulong,名称为隐式常量表达式转换

标签: c# .net


【解决方案1】:

我一直在对此进行试验,使用 ILSpy 来检查输出,这就是我发现的。

显然,在您的第二种情况下,这是一个错误 - 您无法比较 ulongint 因为没有可以强制两者的类型。 ulong 对于long 来说可能太大,int 可能是负数。

但是,在您的第一种情况下,编译器很聪明。它意识到 const 1 > const 32 永远不会正确,并且根本不会在编译输出中包含您的 if 语句。 (它应该对无法访问的代码发出警告。)如果您定义和使用 const int 而不是文字,或者即使您明确地转换文字(即(int)32),也是一样的。

但是编译器不是成功地将ulongint进行比较,我们刚才说这是不可能的吗?

显然不是。那么 发生了什么?

尝试按照以下方式做一些事情。 (获取输入并写入输出,因此编译器不会编译任何内容。)

const int thirtytwo = 32;
static void Main(string[] args)
{
    ulong x = ulong.Parse(Console.ReadLine());
    bool gt = x > thirtytwo;
    Console.WriteLine(gt);
}

这将编译,即使ulong 是一个变量,即使编译时结果未知。看看 ILSpy 中的输出:

private static void Main(string[] args)
{
    ulong x = ulong.Parse(Console.ReadLine());
    bool gt = x > 32uL;        /* Oh look, a ulong. */
    Console.WriteLine(gt);
}

因此,编译器实际上将您的const int 视为ulong。如果您创建thirtytwo = -1,代码将无法编译,即使我们知道gt始终为真。编译器本身无法将ulongint 进行比较。

另请注意,如果您将x 设为long 而不是ulong,编译器会生成32L 而不是32 作为整数,即使它没有 em>到。 (您可以在运行时比较 intlong。)

这表明编译器在第一种情况下没有将32 视为ulong,因为它必须,仅仅因为它可以匹配@的类型987654352@。它使运行时不必强制常量,这只是当强制应该不可能的时候的奖励。

【讨论】:

  • 这是一本非常有趣的读物,为您的研究提供了支持。
  • @Amicable - 向推荐一个有趣的问题,让我想研究它:)
  • C# 编译器与此处的 C# 语言规范完全一致。当int 类型的表达式是编译时常量时,确实存在从intulongimplicit constant expression conversion只要该值在ulong 的范围内,即非负数,这是 C# 编译器可以通过常量表达式看到的。 32int 类型的常量表达式。当int 类型的表达式不是编译时常量时,不存在到ulong 的隐式转换。示例compare.
  • “因为没有一种类型可以强制两者”——谢谢!
【解决方案2】:

给出此错误消息的不是 CLR,而是编译器。

在您的第一个示例中,编译器将32 视为ulong(或可隐式转换为ulong 的类型,例如uint),而在您的第二个示例中,您已将类型显式声明为int .接受 ulongint> 运算符没有重载,因此会出现编译器错误。

【讨论】:

  • 整数文字页面 (msdn.microsoft.com/en-us/library/aa664674.aspx) 说“如果文字没有后缀,则它具有可以表示其值的第一个类型:int、uint、long、ulong。”另外,我的 Intellisense(工具提示)说 32int。但这似乎是正在发生的事情......
  • @Rawling 非常正确,我可以看到三个可能的原因(我敢说还有更多):#1 可能是因为对“值可以表示”的不同解释,即编译器知道 32 不能是一个 int ,因为代码不会编译并尝试 uint next 成功。 Intellisense 显然不会评估整个表达式来计算类型,int 通常是正确的,所以为什么要为边缘情况牺牲计算时间。 #2 整数文字的文档已过时。或者 #3 它是一个编译器错误。
  • @Rawling - 没有错误,它的工作方式与应有的完全一样。文字32 被视为long。您甚至可以引用声明将其视为long
  • @ramhound 你也不能比较长。
  • @rich 实际上,在与 ILSpy 进一步合作之后,我可以看到您是对的。编译器实际上确实将32 处理为ulong,根据我的阅读,它应该被视为int。它是否继续编译是一个单独的问题。
【解决方案3】:

rich.okelly 和 rawling 的答案是正确的,因为您不能直接比较它们。您可以使用Convert 类的ToUInt64 方法来提升int。

if (mask > 0 & (ulong)Permissions.ViewListItems > Convert.ToUInt64(compare))
{
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-27
    • 2023-04-07
    • 1970-01-01
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 2015-01-25
    • 2011-12-31
    相关资源
    最近更新 更多