首先:我知道如何解决这个问题。我不是在寻找解决方案。我对设计选择背后的原因感兴趣,导致一些隐含的转换并且没有导致其他转换。
今天我在代码库中遇到了一个小而有影响的错误,其中int
常量用相同数字的char
表示初始化。这导致ASCII
将char
转换为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'
这种转换是我的拙见,非常符合逻辑。它不会导致数据丢失,作者的意图也很清楚。此外,在我阅读char
对int
隐式转换的其余答案之后,我仍然没有看到为什么这不合法的任何理由。
这就引出了我的实际问题:
C#设计团队有什么理由可以实现从char
到string
的隐式转换,而它的外观看起来很明显(特别是在将它与char
与int
转换进行比较时)。
首先,正如我总是说有人问“为什么不呢?”关于C#的问题:设计团队没有必要提供不做功能的理由。具有成本时间,精力和金钱,而且您所做的每项功能都需要时间,精力和金钱,而不是更好的功能。
但我不想只是拒绝这个前提;问题可能更好地表达为“这个拟议特征的设计优缺点是什么?”
这是一个完全合理的功能,有些语言允许您将单个字符视为字符串。 (Tim在评论中提到了VB,而且Python也将字符和单字符字符串视为可互换的IIRC。我确信还有其他字符串。)但是,如果我提出这个功能,我会指出一些缺点:
.Length
吗?如果我可以将char传递给期望string
的方法,并且我可以将字符串传递给期望IEnumerable<char>
的方法,我可以将char
传递给期望IEnumerable<char>
的方法吗?这似乎......很奇怪。我可以在字符串上调用Select
和Where
;我可以上char吗?这似乎更奇怪。所有提议的功能都是移动您的问题;如果它被实现了,你现在要问“为什么我不能在Char上调用Select?”或某些这样的事情。List<char>
?为什么要停止使用char
?我们应该说int
可兑换成IEnumerable<int>
吗?Task<char>
的明显转换 - 只需创建一个返回char的已完成任务 - 和Func<char>
- 只需创建一个返回char的lambda - 和Lazy<char>
,以及Nullable<char>
- 哦,等等,我们允许转换为Nullable<char>
。 :-)所有这些问题都是可以解决的,有些语言已经解决了。那不是问题。问题是:所有这些问题都是语言设计团队必须识别,讨论和解决的问题。语言设计的一个基本问题是这个功能应该如何通用?在两分钟内,我已经从“字符可转换为单字符字符串”变为“基础类型的任何值可转换为monadic类型的等效值”。对于这两个特征以及关于通用性的各种其他观点,都有一个论点。如果您使语言功能过于具体,则会成为大量特殊情况,彼此之间的互动性很差。如果你使它们太笼统,那么,我猜你有Haskell。 :-)
假设设计团队得出关于该特性的结论:所有这些都必须写在设计文档和规范中,代码和测试必须写入,哦,我是否在任何时候提到过对可兑换规则进行更改,某人的重载解析代码中断了吗?您必须在第一个版本中获得正确的可转换性规则,因为稍后更改它们会使现有代码更加脆弱。有实际的设计成本,如果您在版本8而不是版本1中进行此类更改,则实际用户会有实际成本。
现在比较这些缺点 - 我相信还有更多我没有列出 - 的好处。好处很小:你可以避免单次调用ToString
或+ ""
或者你做什么来明确地将char转换为字符串。
这甚至不足以证明设计,实施,测试和向后兼顾成本的合理性。
就像我说的那样,它是一个合理的功能,并且它已经使用了该语言的第1版 - 它没有泛型,或者已经安装了数十亿行代码 - 那么它本来就更容易销售。但是现在,有很多功能对于小型降压有更大的影响。
Char
是一种价值类型。不,它不是像int
或double那样的数字,但它仍然来自System.ValueType
。然后char
变量存在于堆栈中。
String
是一种参考类型。所以它生活在堆上。如果要将值类型用作引用类型,则需要先将其打包。编译器需要确保你知道你正在通过拳击做什么。所以,你不能有一个隐式演员。
因为当你向char
进行int
的演员表时,你不只是改变它的'类型,你在ASCII表中获得它的'索引是一个非常不同的东西,他们不会让你“将一个字符转换为一个int“他们正在为您提供有用的数据以满足可能的需求。
为什么不让char
演员到string
?
因为它们实际上代表了很多不同的东西,并以不同的方式存储。
char和string不是表达同一事物的两种方式。