【问题标题】:Implicit type cast of char to int in C#在 C# 中将 char 隐式类型转换为 int
【发布时间】:2009-10-01 11:36:25
【问题描述】:

我有一个关于隐式类型转换的问题

为什么这种隐式类型转换在 C# 中起作用?我了解到隐式代码通常不起作用。

我这里有一个关于隐式类型转换的代码示例

 char c = 'a';
 int x = c;
 int n = 5;
 int answer = n * c;
 Console.WriteLine(answer);

【问题讨论】:

  • 这实际上是一个非常好的问题。在 C 中,字符或多或少是字节的同义词,它们都是数字类型。但在 C# 中,字符是 unicode 字符...
  • 所以答案是因为该字符是一个 unicode 字符,这就是它在 C# 中工作的原因?
  • 只是为了纠正您对行话的使用——这不是隐式转换。这是一种隐式转换。 “铸造”是使用铸造操作符;隐式转换是不需要强制转换运算符的转换。
  • Matthew:在 .NET 中,字符可以是来自 BMP 的 Unicode 字符,也可以是代理字符。 Afaik 无法将来自星界的角色放入单个 char。
  • @Eric:为了吹毛求疵,cast 一词可以这样应用,因为它意味着扭曲或扭曲,也可以意味着计算。所以隐式演员对我来说非常有意义......

标签: c#


【解决方案1】:

更新:我今天使用这个问题作为我博客的主题。谢谢你的好问题。请参阅博客了解未来的添加、更新、cmets 等。

http://blogs.msdn.com/ericlippert/archive/2009/10/01/why-does-char-convert-implicitly-to-ushort-but-not-vice-versa.aspx


我并不完全清楚你到底在问什么。 “为什么”的问题很难回答。但我会试一试。

首先,具有从 char 到 int 的隐式转换的代码(注意:这不是“隐式转换”,这是“隐式转换”)是合法的,因为 C# 规范明确指出存在从 char 到 int 的隐式转换char 到 int,编译器在这方面是规范的正确实现。

现在,您可能会明智地指出,该问题已被彻底提出​​。为什么存在从 char 到 int 的隐式转换?为什么语言的设计者认为这是添加到语言中的明智规则?

嗯,首先,阻止这成为语言规则的显而易见的事情并不适用。 char 实现为无符号 16 位整数,表示 UTF-16 编码中的字符,因此可以将其转换为 ushort 而不损失精度,或者就此而言,不改变表示。运行时只是从将此位模式视为 char 到将相同的位模式视为 ushort。

因此可能允许从 char 转换为 ushort。现在,仅仅因为某事是可能的并不意味着它是一个好主意。显然,该语言的设计者认为将 char 隐式转换为 ushort 是一个好主意,但将 ushort 隐式转换为 char 则不是。 (并且由于 char 到 ushort 是一个好主意,char-to-anything-that-ushort-goes-to 似乎也是合理的,因此,char 到 int。另外,我希望清楚为什么允许 explicit ushort 到 char 的转换是明智的;你的问题是关于隐式转换。)

所以我们在这里实际上有两个相关的问题:首先,为什么允许从 ushort/short/byte/sbyte 到 char 的隐式转换是一个坏主意?第二, 为什么允许从 char 到 ushort 的隐式转换是个好主意?

与您不同,我可以使用语言设计团队的原始笔记。通过这些挖掘,我们发现了一些有趣的事实。

第一个问题包含在 1999 年 4 月 14 日的注释中,其中出现了从字节转换为字符是否合法的问题。 在 C# 的原始预发布版本中,这在很短的时间内是合法的。我对注释进行了轻微的编辑以使其清晰,而无需了解 1999 年时代的预发布 Microsoft 代号。我还强调了重点:

[语言设计委员会]选择提供 从字节到的隐式转换 字符,因为一个的域是 完全被对方包容。 然而,现在,[运行时 library] 仅提供 Write 方法 采用字符和整数,这意味着 该字节打印为字符 因为那最终是最好的 方法。我们可以通过以下方式解决这个问题 在 Writer 上提供更多方法 类或通过删除隐式 转换。

有一个论据来解释为什么 后者是正确的做法。 毕竟,字节真的不是 字符。确实,可能有一个 有用的映射 从字节到字符,但最终,23 并不表示 与 ascii 的字符相同 值 23,与 23B 相同 表示与 23L 相同的东西。问 [图书馆作者]提供这个 附加方法仅仅是因为 我们的类型系统中的一个怪癖是如何工作的 out 似乎比较弱。所以我会 建议我们进行转换 从字节到字符显式。

笔记最后得出结论,byte-to-char 应该是显式转换,integer-literal-in-range-of-char 也应该是显式转换。

请注意,语言设计说明没有说明为什么 ushort-to-char 同时也被定为非法,但您可以看到同样的逻辑适用。当调用重载为 M(int) 和 M(char) 的方法时,当您将 ushort 传递给它时,您很可能希望将 ushort 视为一个数字,而不是一个字符。而且 ushort 不是字符表示,就像 ushort 是数字表示一样,因此将这种转换设为非法似乎也是合理的。

1999 年 9 月 17 日决定让 char 转到 ushort;那天关于这个主题的设计说明只是简单地说“char 到 ushort 也是一种合法的隐式转换”,就是这样。注释中没有进一步说明语言设计者那天脑子里发生的事情。

但是,对于为什么隐式 char-to-ushort 被认为是一个好主意,我们可以做出 有根据的猜测。这里的关键思想是从数字到字符的转换是一种“可能不可靠”的转换。它把你不知道的东西当作一个角色,并选择把它当作一个角色来对待。这似乎是您想要明确指出您正在做的事情,而不是意外允许它。但反过来就没有那么狡猾了。在 C 编程中,将字符视为整数有着悠久的传统——获取它们的基本值,或者对它们进行数学运算。

简而言之:使用数字作为字符可能是意外和错误似乎是合理的,但使用字符作为数字是故意和可取的似乎也是合理的。因此,这种不对称性反映在语言规则中。

这能回答你的问题吗?

【讨论】:

  • 如果这在 C# 中开箱即用(有时)仍然会很好,就像在 C 中一样: for (char letter = 'A'; letter
  • 作为记录,以上在 C# 中确实有效,语法稍多:letter = (char)(letter + 2)
  • @Matthew letter += (char)2 也有效,尽管一个字母加上 STX 等于另一个字母并不完全直观。 @卢卡斯∞
  • 我很想知道为什么你不能在 VB.NET 中从 Char 转换为 Integer。看起来底层实现应该是相同的,因此实现起来不是问题。
  • 这是一个示例,说明为什么这种隐式转换对我来说似乎是一个错误,这就是我最终到达此页面的方式。我有三种方法:WriteString(string value)、WriteString(string value, int length) 和WriteString(string value, int length, char padChar)——第一种用于编写可变长度的字符串,另外两种用于固定长度。 WriteString(foo, ' ') 形式的错误调用(调用者省略了长度)编译没有任何问题,因为第二个 WriteString 重载被编译器解决而没有警告。
【解决方案2】:

基本思想是导致潜在数据丢失的转换可以是隐式的,而可能导致数据丢失的转换必须是显式的(例如,使用强制转换运算符)。

因此,从 char 隐式转换为 int 将在 C# 中工作。

[编辑]正如其他人指出的那样,char 是 C# 中的 16 位数字,因此这种转换只是从 16 位整数到 32 位整数,这可能不会丢失数据。 [/编辑]

C# 支持隐式转换,“通常不起作用”的部分可能来自其他语言,可能是 C++,其中一些出色的 string 实现提供了对各种指针类型的隐式转换,从而在应用程序中产生了一些巨大的错误.

当您使用任何语言提供类型转换时,您还应该默认默认为显式转换,并且只为特殊情况提供隐式转换。

【讨论】:

  • 那么是什么解释了为什么在 C# 中没有从 short 到 char 的隐式转换?这可以无损地完成;你的逻辑表明应该有一个从short到char的隐式转换,但没有。为什么不呢?
  • 这就是我说“基本思想”的原因,因为我是从“CLR via C#”一书中得到的。 Dzmitry Huba 引用了参考文献中的最后一句话。我不知道这个决定的理由,但我希望他们试图稍微改善字符和数字之间的语义差异,类似于必须在调用站点上标记 ref 和 out 参数。跨度>
  • 确实如此。事实证明,我确实对这个决定的基本原理有所了解。你的猜想是正确的。 :)
【解决方案3】:

来自 C# 规范

6.1.2 隐式数字转换 隐式数字转换是:

• 从 sbyte 到 short、int、long、 浮点数、双精度数或十进制数。

• 从字节到短,ushort,int, uint、long、ulong、float、double 或 十进制。

• 从 short 到 int、long、float、 双精度或小数。

• 从 ushort 到 int、uint、long、 ulong、float、double 或 decimal。

• 从 int 到 long、float、double 或 十进制。

• 从 uint 到 long、ulong、float、 双精度或小数。

• 从 long 到 float、double 或 十进制。

• 从 ulong 到 float、double 或 十进制。

• 从 char 到 ushort、int、uint、 long、ulong、float、double 或 十进制。

• 从浮点数到双精度数。

从 int、uint、long 或 ulong 浮动和从 long 或 ulong 加倍可能会导致损失 精确,但绝不会造成损失 量级。另一个隐含的 数字转换永远不会丢失任何 信息。没有隐含的 转换为 char 类型,所以 其他整数类型的值 不会自动转换为字符 输入。

【讨论】:

    【解决方案4】:

    来自关于 char 的 MSDN 页面 (char (C# Reference):

    char 可以隐式转换为 ushort、int、uint、long、ulong、float、double 或 decimal。但是,没有从其他类型到 char 类型的隐式转换。

    这是因为他们已经实现了从 char 到所有这些类型的 implicit method。现在,如果您问他们为什么要实现它们,我真的不确定,当然是为了帮助处理字符的 ASCII 表示或类似的东西。

    【讨论】:

    • 是的,这就是为什么我也想知道,我是编程新手,但正如我的老师解释的那样,我看到了它的不一致之处。尤其是在C#中,他们对OO的规则非常严格,应该一直很干净,这很令人惊讶。
    • ´char´ 没有显式地 实现“隐式转换”。如果你用反射器看 Char 源,你看不到任何这些。一些转换对语言本身是隐含的。
    【解决方案5】:

    投射会导致数据丢失。这里char 是 16 位,int 是 32 位。所以演员会在不丢失数据的情况下发生。

    现实生活中的例子:我们可以在没有外部帮助的情况下将小容器放入大容器中,但反之亦然。

    【讨论】:

    • 不,强制转换并不总是会导致数据丢失,例如long l = (long)300;
    【解决方案6】:

    之所以有效,是因为每个字符在内部都作为数字处理,因此强制转换是隐式的。

    【讨论】:

    • 虽然看似合理,但这种推理实际上并不合乎逻辑。如果这是推理,那么会有从 ushort 到 char 的隐式转换,但没有这样的隐式转换。
    【解决方案7】:

    char 被隐式​​转换为它的 Unicode 数值,它是一个整数。

    【讨论】:

    • char 类型表示 unicode 字符。在 65,536 个可能的 char 值中,只有 128 个具有 ASCII 等价物。
    • 你说得对,我不确定我在想什么...已编辑。
    【解决方案8】:

    在我看来,从 char 类型到数字类型的隐式转换没有意义,因为会丢失信息。你可以从这个例子中看出:

    string ab = "ab";
    char a = ab[0];
    char b = ab[1];
    var d = a + b;   //195
    

    我们已将字符串中的所有信息都放入字符中。如果仅保留来自 d 的信息,那么留给我们的只是一个在这种情况下毫无意义的数字,并且不能用于恢复先前提供的信息。因此,最有用的方法是将字符的“总和”隐式转换为字符串。

    【讨论】:

      【解决方案9】:

      @Eric Lippert 的 blog entry 的核心是他对 c# 语言设计者做出这一决定背后原因的有根据的猜测:

      "There is a long tradition in C programming of treating characters as integers 
      -- to obtain their underlying values, or to do mathematics on them."
      

      但它可能会导致错误,例如:

      var s = new StringBuilder('a');
      

      您可能会认为使用“a”字符来初始化 StringBuilder,but actually sets the capacity of the StringBuilder to 97。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-17
        • 1970-01-01
        • 2017-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多