【问题标题】:Implicit conversion from char to single character string从 char 到单个字符串的隐式转换
【发布时间】:2019-02-15 17:47:12
【问题描述】:

首先:我知道如何解决这个问题。我不是在寻找解决方案。我对导致一些隐式转换而没有导致其他转换的设计选择背后的原因很感兴趣。

今天我在我们的代码库中遇到了一个小但有影响力的错误,其中int 常量被初始化为相同数字的char 表示。这导致ASCIIchar 转换为int。像这样的:

char a = 'a';
int z = a;
Console.WriteLine(z);    
// Result: 97

我很困惑为什么 C# 会允许这样的事情。在四处搜索后,我发现了以下 SO 问题以及 Eric Lippert 本人的回答:Implicit Type cast in C#

摘录:

但是,我们可以对为什么隐式进行有根据的猜测 char-to-ushort 被认为是一个好主意。这里的关键思想是 从数字到字符的转换是“可能是狡猾的” 转换。它正在采取一些你不知道的意图 成为一个角色,并选择将其视为一个角色。这似乎是 你想明确指出你正在做的事情, 而不是意外地允许它。但相反的要少得多 狡猾。 C 编程中有一个悠久的传统 作为整数的字符——获取它们的基础值,或者做 数学。

我同意它背后的原因,尽管 IDE 提示会很棒。但是,我还有另一种情况,隐式转换突然合法:

char a = 'a';
string z = a; // CS0029 Cannot implicitly convert type 'char' to 'string'

以我的拙见,这种转换非常合乎逻辑。它不会导致数据丢失,并且作者的意图也很明确。此外,在我阅读了关于 charint 隐式转换的其余答案后,我仍然看不出这不合法的任何理由。

这就引出了我的实际问题:

C# 设计团队有什么理由不实现从 charstring 的隐式转换,虽然它看起来如此明显(尤其是与 char 到 @ 相比时) 987654334@转换)。

【问题讨论】:

  • 顺便说一下,char->string 在 VB.NET 中完全有效(即使 Option Strict On 也是如此)。使用 Option Strict Off 时,即使 string->char 也是有效的(字符串的第一个字符被占用,真是一团糟)。

标签: c# .net implicit-conversion language-design


【解决方案1】:

首先,当有人问“为什么不呢?”时,我总是这么说。关于 C# 的问题:设计团队不必提供做某项功能的理由。功能需要时间、精力和金钱,而您所做的每一项功能都需要时间、精力和金钱来实现更好的功能。

但我不想直接拒绝这个前提;这个问题可能更好地表述为“这个提议的功能的设计优点和缺点是什么?”

这是一个完全合理的功能,并且有些语言允许您将单个字符视为字符串。 (Tim 在评论中提到了 VB,Python 也将字符和单字符字符串视为可互换的 IIRC。我相信还有其他的。)但是,如果我提出了这个功能,我会指出一些缺点:

  • 这是一种新的拳击转换形式。字符是廉价的价值类型。字符串是堆分配的引用类型。装箱转换可能会导致性能问题并产生收集压力,因此有一个论点是它们应该在程序中更明显,而不是更不明显。
  • 该功能不会被视为“字符可转换为单字符字符串”。用户会认为它是“字符单字符的字符串”,现在问很多连锁问题是完全合理的,比如:可以在字符上调用.Length吗?如果我可以将一个字符传递给一个需要string 的方法,并且我可以将一个字符串传递给一个需要IEnumerable<char> 的方法,我可以将char 传递给一个需要IEnumerable<char> 的方法吗?这似乎……很奇怪。我可以在一个字符串上调用SelectWhere;我可以在一个字符上吗?这似乎更奇怪了。所有提议的功能都是移动你的问题;如果它被实施,你现在会问“为什么我不能在一个字符上调用 Select?”或类似的东西。

  • 现在将前两点组合在一起。如果我将 chars 视为一个字符的字符串,并且将 char 转换为对象,我得到的是 boxed char 还是 string?

  • 我们还可以进一步概括第二点。字符串是字符的集合。如果我们要说一个 char 可以转换为一个 char 集合,为什么要停止使用字符串呢?为什么不也说一个字符也可以用作List<char>?为什么停止使用char?我们是否应该说int 可以转换为IEnumerable<int>
  • 我们可以进一步概括:如果从 char 到 string-of-chars-in-a-string 有明显的转换,那么也有从 char 到 Task<char> 的明显转换——只需创建一个已完成的任务返回 char -- 并返回到 Func<char> -- 只需创建一个返回 char 的 lambda -- 以及 Lazy<char>Nullable<char> -- 哦,等等,我们允许转换为Nullable<char>。 :-)

所有这些问题都是可以解决的,一些语言已经解决了这些问题。那不是问题。问题是:所有这些问题都是语言设计团队必须识别、讨论和解决的问题。语言设计中的一个基本问题是这个功能应该有多通用?在两分钟内,我已经从“字符可转换为单字符串”到“基础类型的任何值都是可转换为一元类型的等效值”。对于这两个特征以及普遍性范围内的其他各种点,都有一个论据。如果你让你的语言特性过于具体,它就会变成大量的特殊情况,它们之间的交互很差。如果你让它们太笼统,那么,我猜你有 Haskell。 :-)

假设设计团队就该特性得出结论:所有这些都必须写在设计文档和规范、代码和测试中,而且,哦,我是否提到过每当您更改可兑换规则时,有人的重载解析代码会中断吗?您必须在第一个版本中正确使用可转换性规则,因为稍后更改它们会使现有代码更加脆弱。如果您在第 8 版而不是第 1 版中进行此类更改,则会产生实际的设计成本,并且对于实际用户而言也会产生实际成本。

现在将这些缺点(我敢肯定还有更多我没有列出)与优点进行比较。好处非常小:您避免了一次调用 ToString+ "" 或任何将字符显式转换为字符串的操作。

这还不足以证明设计、实施、测试和破坏向后兼容的成本是合理的。

就像我说的,这是一个合理的特性,如果它是语言的第 1 版——它没有泛型,或者安装了数十亿行代码——那么它会容易得多卖。但现在,有很多功能物超所值。

【讨论】:

  • 哇,感谢您提供如此详细的答案。我希望你能回答它,我只是没想到它真的会发生;-) 我想我会错过很多事情,最重要的是概括。我也考虑过性能,但我倒退了。这不是您要避免的性能成本,而是您看不到成本的事实。您的回答最有帮助,可惜我只能投票并标记一次。谢谢!
  • 哦,我确实提出了错误的问题。在软件开发中平衡利弊和有限的开发能力始终是一个问题。我工作的地方完全一样(我想无处不在)。我将编辑问题的那一部分,以免它对 C# 设计团队造成如此负面的影响。
【解决方案2】:

Char 是一个值类型。不,它不是像 int 或 double 那样的数字,但它仍然派生自 System.ValueType。然后一个char 变量存在于堆栈中。

String 是一个引用类型。所以它存在于堆上。如果要将值类型用作引用类型,则需要先将其装箱。编译器需要确保您通过装箱知道自己在做什么。所以,你不能有一个隐式转换。

【讨论】:

    【解决方案3】:

    因为当您将 char 转换为 int 时,您不仅会更改其类型,还会在 ASCII 表中获取其索引,这是完全不同的事情,他们不会让您可以“将 char 转换为 int”,它们会为您提供可能需要的有用数据。

    为什么不让char 的演员表转为string

    因为它们实际上代表了许多不同的事物,并且以完全不同的方式存储。

    char 和 string 不是表达同一事物的两种方式。

    【讨论】:

    • 你当然是改类型了,char和int是两种不同的类型
    • @pyrocumulus:C# 是 C 的衍生品,数以百万计的开发人员将 chars 视为 int 并使用它们进行计算。所以这是一个悠久的传统。 char->string 的情况并非如此。
    • @pyrocumulus 成本更高
    • 字符不是 ASCII 字符。字符是 UTF-16 代码单元。如果 char 的高 9 位为零,则低 7 位是有效的 ASCII 码,但您不应将 chars 视为 ASCII;这是一种误导和不正确的描述。
    • @pyrocumulus:如果我曾经暗示历史原因并不重要,那么我在解释自己方面做得很差。符合现有 C、C++ 和 Java 用户的直觉和期望是 C# 设计的基础。 C# 通常被描述为对 Java 的回应,这有一定道理,但更准确的说法是 C# 和 Java 共享相同的设计目标:制作更安全的 C。事实上,前两个代号为C# 项目是“COOL”,代表“C-like Object-Oriented Language”和“SafeC”。
    猜你喜欢
    • 2013-05-13
    • 2011-10-24
    • 2014-02-04
    • 1970-01-01
    • 2020-09-30
    • 1970-01-01
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多