为什么没有像String.Empty一样的Char.Empty?

319

这是有原因的吗?我问这个问题是因为如果您需要使用大量的空字符,那么您会遇到使用大量空字符串时相同的情况。

编辑:这种用法的原因是:

myString.Replace ('c', '')

请从myString中删除所有 'c' 的实例。


1
是的,我用那个词是因为没有更好的词了。即推荐使用String.Empty而不是“”。 - Joan Venge
3
如果你担心有时会因打错而出现问题,为什么不简单地将功能包装在扩展方法中,例如RemoveAll(this string s, params char[] toRemove)?这样就可以清晰地传达意图,同时避免出错。 - bzlm
12
我使用string.Empty的唯一原因是,我认为Empty提供的空对象比空引号更能表达意图。空引号可能来源于合并问题、思维混乱,或者本来就是代码的实际意图,而Empty明确告诉我开发人员打算让该字符串不包含数据。 - Ritch Melton
3
""和string.Empty之间有区别。虽然没有人真的关心,但是""会创建一个对象,而string.Empty则利用已经创建好的对象。但是这个区别非常小,在普通情况下不会有任何影响。 - marcelo-ferraz
4
关于@marcelo-ferrazm所说的“""创建一个对象”:不,它并没有这样做。 - H H
显示剩余2条评论
23个回答

319

不存在空字符这样的东西。你能得到的最接近的是Unicode编码的 "null" 字符:'\0'。考虑到你可以很容易地将它嵌入字符串字面值或单独表达它,为什么还要为它单独设置一个字段呢?同样,"很容易混淆""" "参数" 的论点不适用于'\ 0'

如果你能举出想要使用它的例子以及你认为它会更好的原因,那可能会有所帮助...


2
\0 不是字节数组的结束字符吗?还是我和其他东西混淆了? - Bertvan
5
为什么一个字节数组的末尾会有一个字符呢?虽然它通常用于“空结尾”字符串,是吗? - Jon Skeet
46
Char.MinValue比'\0'更好。 - Aliostad
10
如果有一个类似于 Int32.Zero 的字段,你会使用它来代替字面量 0 吗?如果不会,那么这里有什么区别? - Jon Skeet
8
@Adam,@Jon -- “bell”的代码是什么?还是退格键更好,想一想... 或者也许不必考虑,直接写Char.Backspace?另一个原因是-- 你说最好为终止符写 '0',相反,应该写Char.Terminator,但其实不是这样--很容易出现拼写错误(完全编译,见上文),尝试写Char.Termnator。有足够的理由避免使用非可检查的原始值(太多愚蠢的拼写错误导致航天任务失败)。 - greenoldman
显示剩余22条评论

222

这种用法的原因是这样的:myString.Replace('c', '') 所以从myString中删除所有实例'c'

要从字符串中删除特定字符,您可以使用字符串重载:

 myString = myString.Replace ("c", String.Empty);

您的声明

 myString.Replace ('c', '\0')

不会删除任何字符。它只会用'\0'(字符串结尾,EOS)替换它们,并产生不同的后果。一些字符串操作在遇到EOS时可能会停止,但在.NET中,大多数操作将像对待任何其他字符一样处理它。最好尽可能避免使用'\0'


24
希望这个能得到更多投票,因为这是实际的解决方案。 - Oren Mazor
3
@OrenMazor,不是的。这个回答甚至没有试图回答问题。问题是“为什么没有像 String.Empty 一样的 Char.Empty?” - David Murdoch
3
@DavidMurdoch - 是的,问题并不总是表面看起来的样子。 - H H

101

字符(Char)与字符串(String)不同,它是一个具有固定大小的离散对象。字符串实际上是一组字符的集合。

因此,在这种情况下,Char.Empty并没有实际意义。如果你有一个字符,它就不是空的。


5
没错。询问容器是否为空是有意义的,但询问整数、浮点数或字符是否为空是没有意义的。 - T.E.D.
1
@Joe:那么如果字符串是(非空)字符的集合,怎么可能为空呢?可能很愚蠢,抱歉... - user1477388
18
因为一个字符串不是单独的对象,而是一个集合。可以把它想象成一桶石头。我不可能有一块空的石头,但是我可以有一只空的桶。 - Joe
2
我会将其表述为“char是原始值类型,而string是非原始引用类型”。 - samus

37

没有所谓的空字符。它总是包含某些东西。即使'\0'也是一个字符。


33

使用Char.MinValue,它与 '\0' 相同。但请注意,它与 String.Empty 不同。


1
谢谢,我之前没见过。你知道它在 myString.Replace('c', Char.MinValue) 中是否起作用吗?我应该试一下。 - Joan Venge

20

这允许“?”还是只有null? - Joan Venge
在您的情况下,您可以这样做:myString.Replace("c", (c == null ? "" : c.ToString()))。 - paquetp

14

这并非回答你的问题,但是要表示 char 的默认值,你可以使用

default(char)

这与char.MinValue相同,后者又等同于\0。但不应将其用于像空字符串之类的内容。


13
myString = myString.Replace('c'.ToString(), "");

好的,这种方法并不是特别优雅地删除字母,因为.Replace方法有一个接受字符串参数的重载。但是这个方法可以用来删除回车、换行符、制表符等。下面的例子是删除制表符:

myString = myString.Replace('\t'.ToString(), "");

myString = myString.Replace("\t", ""); 这个不是更短更清晰吗? - Heretic Monkey

13

如果您不需要整个字符串,可以利用延迟执行的优势:

public static class StringExtensions
{
    public static IEnumerable<char> RemoveChar(this IEnumerable<char> originalString, char removingChar)
    {
        return originalString.Where(@char => @char != removingChar);
    }
}

您甚至可以组合多个字符来创建更复杂的正则表达式。下面是一些常用的特殊字符:

string veryLongText = "abcdefghijk...";

IEnumerable<char> firstFiveCharsWithoutCsAndDs = veryLongText
            .RemoveChar('c')
            .RemoveChar('d')
            .Take(5);

...并且只有前7个字符会被评估 :)

编辑:或者,更好的方法:

public static class StringExtensions
{
    public static IEnumerable<char> RemoveChars(this IEnumerable<char> originalString,
        params char[] removingChars)
    {
        return originalString.Except(removingChars);
    }
}

及其使用:

        var veryLongText = "abcdefghijk...";
        IEnumerable<char> firstFiveCharsWithoutCsAndDs = veryLongText
            .RemoveChars('c', 'd')
            .Take(5)
            .ToArray(); //to prevent multiple execution of "RemoveChars"

@Joan:谢谢...即使“天才”有点夸张 :P(我不知道当removingChars变成一个大数组时它的表现如何...) - Notoriousxl
1
昨天我忘了:注意如何使用结果变量“firstFiveCharsWithoutCsAndDs”。如果您不想将其传递给另一个“yield”方法(例如LINQ中的方法),在“Take(5)”之后立即调用“.ToArray()”...否则,“RemoveChars + Take”链将每次以“传统”的方式访问变量时执行(例如,在每次调用“Count()”时或在未使用“yield return”遍历它时)。 - Notoriousxl
+1 很好的想法。但是这种方法无法像基本方法一样易于维护和高效 :) - nawfal
1
@nawfal 从效率上讲,你是对的,但我认为myString.Except("c")比myString.Replace('c', '')更具有声明性:P(而且它可以很好地扩展:myString.Except("aeiou")) - Notoriousxl

8
同样的原因,就像没有int.Empty一样。容器可以为空,标量值不能。如果你指的是0(不是空的),那么使用'\0'。如果你指的是null,那么使用null :)

4
"null" 不能作为字符,因为字符是值类型。你需要使用 "char?" 才能将其赋值为 null。 - Femaref
你应该将其设为可空的。请查看我的答案。 - paquetp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接