从char隐式转换为单个字符串 [英] Implicit conversion from char to single character string

查看:71
本文介绍了从char隐式转换为单个字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

我很困惑,为什么C#会允许这样的事情.在四处搜寻之后,我发现了下面的SO问题,其中有Eric Lippert自己的回答:使用C#转换的隐式类型

摘录:

但是,我们可以对为什么隐式做出有根据的猜测 char-to-ushort被认为是一个好主意.这里的关键思想是 从数字到字符的转换是可能是狡猾的" 转换.您正在采取某些您不知道要去做的事情 成为一个角色,并选择将其视为一个角色.好像 您想明确指出自己正在做的事情, 而不是无意间允许它.但是反之则少得多 狡猾. C语言编程中有很长的传统 字符作为整数-获取其基础值或 数学.

我可以同意其背后的理由,尽管IDE提示会很棒.但是,我还有另一种情况,即隐式转换突然合法:

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

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

这使我想到了我的实际问题:

C#设计团队可能有什么理由不实现从charstring的隐式转换,而从外观上看是如此明显(特别是将其与char转换为int转换).

解决方案

首先,正如我经常说的那样,有人问为什么不呢?"有关C#的问题:设计团队不必提供做功能的理由.功能需要花费时间,精力和金钱,而您所做的每个功能都需要花费时间,精力和金钱才能摆脱更好的功能.

但是我不想单枪匹马地拒绝这个前提.这个问题可能更好地表述为此提议功能的设计利弊是什么?"

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

  • 这是装箱转换的一种新形式.字符是便宜的价值类型.字符串是堆分配的引用类型.装箱转换可能会导致性能问题并产生收集压力,因此存在一个论点,即它们应在程序中更可见,而不是不那么可见.
  • 该功能将不会被视为字符可转换为一个字符的字符串".用户会认为它是字符一个字符的字符串",现在问很多连锁问题非常合理,例如:可以在字符上调用.Length吗?如果我可以将char传递给期望string的方法,并且可以将字符串传递给期望IEnumerable<char>的方法,那么我可以将char传递给期望IEnumerable<char>的方法吗?看来...很奇怪.我可以在字符串上调用SelectWhere;我可以喝点酒吗?这似乎更加奇怪.所建议的功能只是提出您的问题;如果实现了该功能,您现在会问:为什么我不能在char上调用Select?"或类似的东西.

  • 现在将前面的两个点合并在一起.如果我将char视为一个字符的字符串,并将char转换为对象,我会得到装箱的char还是字符串?

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

所有这些问题都是可以解决的,有些语言已经解决了它们.那不是问题.问题是:所有这些问题都是语言设计团队必须识别,讨论和解决的问题.语言设计中的基本问题之一是此功能的一般性?在两分钟内,我从字符可转换为单字符字符串"变为任何基础类型的值都是可转换为单价类型的等效值".对于这两个功能以及通用性上的其他各个方面都存在争论.如果您使语言功能过于具体,则会成为大量相互之间无法很好交互的特殊情况.如果您使它们过于笼统,那么,我想您有Haskell. :-)

假设设计团队得出有关该功能的结论:所有这些都必须写在设计文档和规范中,并且必须编写代码和测试,哦,我是否提到了这一点?每当您更改可转换性规则时,某人的重载解决方案代码就会中断?在第一个版本中,您确实必须正确制定可转换性规则,因为稍后对其进行更改会使现有代码更加脆弱.如果您在版本8中而不是版本1中进行此类更改,则将产生实际的设计成本,并且对实际用户也会产生实际成本.

现在比较这些不利因素-我敢肯定还有更多我没有列出的不利因素.好处很小:您避免单个调用ToString+ "",或者避免将char显式转换为字符串的任何操作.

这甚至还不足以证明设计,实施,测试和向后兼容的成本是合理的.

就像我说的那样,这是一个合理的功能,如果它是该语言的第1版-没有泛型,或者安装了数十亿行代码-那么它会容易得多卖.但是现在,有很多功能具有更大的优势,而价格却更低.

First of all: I know how to work around this issue. I'm not searching for a solution. I am interested in the reasoning behind the design choices that led to some implicit conversions and didn't lead to others.

Today I came across a small but influential error in our code base, where an int constant was initialised with a char representation of that same number. This results in an ASCII conversion of the char to an int. Something like this:

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

I was confused why C# would allow something like this. After searching around I found the following SO question with an answer by Eric Lippert himself: Implicit Type cast in C#

An excerpt:

However, we can make educated guesses as to why implicit char-to-ushort was considered a good idea. The key idea here is that the conversion from number to character is a "possibly dodgy" conversion. It's taking something that you do not KNOW is intended to be a character, and choosing to treat it as one. That seems like the sort of thing you want to call out that you are doing explicitly, rather than accidentally allowing it. But the reverse is much less dodgy. There is a long tradition in C programming of treating characters as integers -- to obtain their underlying values, or to do mathematics on them.

I can agree with the reasoning behind it, though an IDE hint would be awesome. However, I have another situation where the implicit conversion suddenly is not legal:

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

This conversion is in my humble opinion, very logical. It cannot lead to data loss and the intention of the writer is also very clear. Also after I read the rest of the answer on the char to int implicit conversion, I still don't see any reason why this should not be legal.

So that leads me to my actual question:

What reasons could the C# design team have, to not implement the implicit conversion from char to a string, while it appears so obvious by the looks of it (especially when comparing it to the char to int conversion).

解决方案

First off, as I always say when someone asks "why not?" question about C#: the design team doesn't have to provide a reason to not do a feature. Features cost time, effort and money, and every feature you do takes time, effort and money away from better features.

But I don't want to just reject the premise out of hand; the question might be better phrased as "what are design pros and cons of this proposed feature?"

It's an entirely reasonable feature, and there are languages which allow you to treat single characters as strings. (Tim mentioned VB in a comment, and Python also treats chars and one-character strings as interchangeable IIRC. I'm sure there are others.) However, were I pitched the feature, I'd point out a few downsides:

  • This is a new form of boxing conversion. Chars are cheap value types. Strings are heap-allocated reference types. Boxing conversions can cause performance problems and produce collection pressure, and so there's an argument to be made that they should be more visible in the program, not less visible.
  • The feature will not be perceived as "chars are convertible to one-character strings". It will be perceived by users as "chars are one-character strings", and now it is perfectly reasonable to ask lots of knock-on questions, like: can call .Length on a char? If I can pass a char to a method that expects a string, and I can pass a string to a method that expects an IEnumerable<char>, can I pass a char to a method that expects an IEnumerable<char>? That seems... odd. I can call Select and Where on a string; can I on a char? That seems even more odd. All the proposed feature does is move your question; had it been implemented, you'd now be asking "why can't I call Select on a char?" or some such thing.

  • Now combine the previous two points together. If I think of chars as one-character strings, and I convert a char to an object, do I get a boxed char or a string?

  • We can also generalize the second point a bit further. A string is a collection of chars. If we're going to say that a char is convertible to a collection of chars, why stop with strings? Why not also say that a char can also be used as a List<char>? Why stop with char? Should we say that an int is convertible to IEnumerable<int>?
  • We can generalize even further: if there's an obvious conversion from char to sequence-of-chars-in-a-string, then there is also an obvious conversion from char to Task<char> -- just create a completed task that returns the char -- and to Func<char> -- just create a lambda that returns the char -- and to Lazy<char>, and to Nullable<char> -- oh, wait, we do allow a conversion to Nullable<char>. :-)

All of these problems are solvable, and some languages have solved them. That's not the issue. The issue is: all of these problems are problems that the language design team must identify, discuss and resolve. One of the fundamental problems in language design is how general should this feature be? In two minutes I've gone from "chars are convertible to single-character strings" to "any value of an underlying type is convertible to an equivalent value of a monadic type". There is an argument to be made for both features, and for various other points on the spectrum of generality. If you make your language features too specific, it becomes a mass of special cases that interact poorly with each other. If you make them too general, well, I guess you have Haskell. :-)

Suppose the design team comes to a conclusion about the feature: all of that has to be written up in the design documents and the specification, and the code, and tests have to be written, and, oh, did I mention that any time you make a change to convertibility rules, someone's overload resolution code breaks? Convertibility rules you really have to get right in the first version, because changing them later makes existing code more fragile. There are real design costs, and there are real costs to real users if you make this sort of change in version 8 instead of version 1.

Now compare these downsides -- and I'm sure there are more that I haven't listed -- to the upsides. The upsides are pretty tiny: you avoid a single call to ToString or + "" or whatever you do to convert a char to a string explicitly.

That's not even close to a good enough benefit to justify the design, implementation, testing, and backwards-compat-breaking costs.

Like I said, it's a reasonable feature, and had it been in version 1 of the language -- which did not have generics, or an installed base of billions of lines of code -- then it would have been a much easier sell. But now, there are a lot of features that have bigger bang for smaller buck.

这篇关于从char隐式转换为单个字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆