C#中的String和string有什么区别?

7511

这两者之间有什么不同,我应该使用哪一个?

string s = "Hello world!";
String s = "Hello world!";

110
@O.R.Mapper,事实仍然存在,string 是 C# 语法的一个 词法 构造,而 System.String 只是一种类型。无论任何规范中提到的 显式 差异如何,仍然存在这种隐含的差异,可能会带来一些歧义。语言本身必须以一种不需要考虑 BCL 中的特定类的方式支持 string - Kirk Woll
146
根据语言规范,该语言本身必须将“string”视为与BCL类型“System.String”完全相同,没有任何其他含义。这一点毫不含糊。当然,你可以使用C#语法实现自己的编译器,并使用找到的所有标记来执行任意的、与C#语言规范定义无关的操作。然而,结果得到的语言只能被视为类似于C#,而不能被视为C#本身。 - O. R. Mapper
125
对于System命名空间的string类型,您无需使用using指令即可直接使用,但是对于String类型则不行。 - Wilsu
27
对于来自Algol和Fortran的人来说,这个讨论表明string存在问题。需要缩写System.String,但作为别名,它看起来非常相似,但不完全相同。然而,经过几年的C#编程,我认为,安全起见,可以直接使用stringstring.Format(),不用担心System.String - Roland
27
@Sangeeta你在说什么?System.String类还在,而string关键字仍然是它的别名,就像System.Int32int一样。它们实际上是同一个东西。 - Craig Tullis
显示剩余11条评论
67个回答

7041

string 在 C# 中是 System.String 的别名。
因此,在技术上,它们没有任何区别。这就像 int vs. System.Int32 一样。

至于指南,通常建议在引用对象时使用 string

例如:

string place = "world";

同样地,我认为通常建议使用String来特别指代这个类。

例如:

string greet = String.Format("Hello {0}!", place);

这是微软在示例中倾向于使用的样式

看起来,这方面的指导可能已经发生了变化,因为StyleCop现在强制使用特定于 C# 的别名。


197
如果您决定使用StyleCop并遵循它,那么它将要求使用特定于语言的类型。因此,在C#中,您应该使用string(而不是String)、int(而不是Int32)和float(而不是Single)- http://stylecop.soyuz5.com/SA1121.html - Dominic Zukiewicz
189
我总是使用别名,因为我认为有一天它可能会派上用场。别名作为抽象层起到了作用,因此可以更改其实现而无需我了解详细信息。 - Rob
63
Visual Studio 2015表示应将String.Format更改为string.Format,所以我猜微软正在朝这个方向发展。我也一直使用String来调用静态方法。 - Sami Kuhmonen
5
你认为自己可以定义自己的类型 "String",但是不能对 "string" 进行同样的操作,因为它是一个关键字。这个问题在 https://dev59.com/O3VD5IYBdhLWcg3wWaRh#27965515 中有详细解释。 - jmoreno
5
我猜那么... 就保持一致吧。使用 string 或 String,或在特定情况下使用某个确定的大小写形式,但始终如此。 - Rob L
显示剩余5条评论

3796

为了充分说明问题,以下是相关信息的大脑转储...

正如其他人所指出的那样,stringSystem.String 的别名。假设您的代码使用 String 编译成 System.String(即您没有使用不同 String 类型的某些其他命名空间的 using 指令),它们编译为相同的代码,因此在执行时没有任何区别。这只是 C# 中的一个别名列表。完整列表如下:

object:  System.Object
string:  System.String
bool:    System.Boolean
byte:    System.Byte
sbyte:   System.SByte
short:   System.Int16
ushort:  System.UInt16
int:     System.Int32
uint:    System.UInt32
long:    System.Int64
ulong:   System.UInt64
float:   System.Single
double:  System.Double
decimal: System.Decimal
char:    System.Char

除了stringobject,所有的别名都是值类型。 decimal是一个值类型,但不是CLR中的原始类型。唯一没有别名的原始类型是System.IntPtr

在规范中,值类型别名被称为“简单类型”。字面量可以用于每个简单类型的常量值;其他值类型没有可用的字面形式。(与VB相比,VB允许DateTime字面量,并且也有一个别名。)

只有一种情况必须使用别名:显式指定枚举的基础类型。例如:

public enum Foo : UInt32 {} // Invalid
public enum Bar : uint   {} // Valid

这只是规范定义枚举声明的方式-冒号后面必须是整数类型,它是、、、、、、、、等一种integral-type标记,而不是变量声明等使用的type标记。这并不表示其他任何区别。

最后,在选择使用哪个方面上:我个人在实现时都使用别名,但是在任何API中都使用CLR类型。就实现而言使用哪个并不太重要-团队内部的一致性很好,但是其他人并不会关心。另一方面,在API中引用类型时以语言中立的方式呈现真的很重要。方法名为ReadInt32是明确无误的,而方法名为ReadInt则需要解释。调用者可能会使用将int别名定义为Int16的语言。.NET框架设计人员遵循了这种模式,在BitConverterBinaryReaderConvert类中有很好的例子。


“CLR中不是原始类型”是什么意思?这意味着如果您在C#代码中使用小数,它将无法与其他.NET语言(如BASIC)互操作? - Haighstrom
@Haighstrom:这不是互操作性的问题,而是CLR指令集没有“decimal”概念。在这方面,它不是原始类型。 - Jon Skeet
我猜我的使用“可互操作性”一词是不正确的,但我的问题是,CLR中没有“decimal”在实际层面上意味着什么?也就是说,如果我在C#代码中编写“decimal”,会有什么限制?这将使我从中创建的.dll文件不符合CLS标准,这意味着我无法将其导入到BASIC项目中? - Haighstrom
2
@Haighstrom:举个例子,这意味着不能在属性中使用“decimal”值。(不过我认为使用“decimal”并不违反CLS规范。) - Jon Skeet

827

String 代表的是 .NET Framework 中的 System.String 类型。在 C# 语言中,string 是对 System.String 的别名。它们都编译成了System.String 在 IL(Intermediate Language)中,所以没有区别。选择你喜欢的并使用它。如果你使用C#编码,我建议使用string,因为它是C#类型的别名,并且被C#程序员广泛认可。

对于其他类型,如(int, System.Int32)等,我也可以这样说。


17
我个人更喜欢使用 "Int32",因为它立即显示了值的范围。想象一下,如果在以后的高位系统上升级了 "int" 类型。 在 C 中,“int” 显然被视为“目标处理器最有效地处理的整数类型”,并定义为“至少 16 位”。 我会更喜欢有可预测的一致性,非常感谢。 - Nyerguds
8
我同意。如果有什么需要做,那就是 始终使用 .net 类型,因为它们与编程语言无关并且类型很明显,不受任何语言的影响(我是否了解所有 F# 或 VB 的特异性?)。 - Peter - Reinstate Monica
24
@Nyerguds,有两个理由可以不必担心它。一是int在C#语言规范中被定义为32位整数,而不考虑硬件。尽管C#与C语言有着共同的历史渊源,但实际上它们并不相同。将int更改为64位整数将会打破规范和语言。这还需要重新定义long,因为long目前是64位整数。另一个没有必要担心的原因是,尽管类型永远不会改变,但.NET足够抽象,以至于99%的时间你根本不需要考虑它。;-) - Craig Tullis
15
@Craig,虽然我经常深入研究许多旧的专有游戏格式,在这些情况下,我必须一直考虑到数据类型。在代码中使用 Int16Int32Int64 要比使用不太具描述性的 shortintlong 更加清晰易懂。 - Nyerguds
9
但是,“short”、“int”、“long”、“float”、“double”等等,都是描述性的,因为它们在语言规范中有明确的定义。C#不同于C语言。我更喜欢在变量声明中使用它们,因为它们简洁、小巧且美观。但是,在API需要依赖于数据类型时,我更喜欢使用Torre库的名称。 - Craig Tullis
1
这都是些纷争。如果我在进行需要计算字节的任务时,我可能会依赖于IntXX,而在其他情况下,我会使用short int long等等。我很感激自己可以任选一种,并会充分利用这种灵活性来最好地满足我的需求。对于我也不理解的这个论点,因为据我所知C/C++根本没有使用intXX别名,而C#则自行引入了它们。虽然如此,这是一个很棒的低级别讨论! - Narish

589

在C#中使用提供的类型别名的最佳答案来自Jeffrey Richter在他的书CLR Via C#中。以下是他的3个原因:

  • 我见过许多开发人员感到困惑,不知道在他们的代码中是否应该使用string还是String。因为在C#中,字符串(一个关键字)恰好映射到System.String(一个FCL类型),所以没有区别,两者都可以使用。
  • 在C#中,long映射到System.Int64,但在另一种编程语言中,long可能映射到Int16Int32。事实上,C++/CLI将long视为Int32。如果某个人习惯于使用不同的编程语言,那么阅读源代码时可能会错误地解释代码的意图。事实上,大多数语言甚至不将long视为关键字,并且不会编译使用它的代码。
  • FCL有许多方法,它们的方法名称中包含类型名称。例如,BinaryReader类型提供了像ReadBooleanReadInt32ReadSingle等方法,而System.Convert类型则提供了像ToBooleanToInt32ToSingle等方法。尽管编写以下代码是合法的,但是第二行使用float感觉非常不自然,而且不明显该行是否正确:
BinaryReader br = new BinaryReader(...);
float val  = br.ReadSingle(); // OK, but feels unnatural
Single val = br.ReadSingle(); // OK and feels good

所以这就是全部内容。我认为这些都是非常好的观点。但是,就我个人而言,在我的代码中并没有使用杰弗里的建议。也许我太过于固执于我的C#世界,但我最终会尝试让我的代码看起来像框架代码。


523

string是一个保留字,但String只是一个类名。这意味着string不能单独用作变量名。

如果出于某种原因你想要一个名为string的变量,你只能编译第一个选项:

StringBuilder String = new StringBuilder();  // compiles
StringBuilder string = new StringBuilder();  // doesn't compile 

如果你真的想要一个名为string的变量名称,你可以使用@作为前缀:

StringBuilder @string = new StringBuilder();

另一个关键区别:Stack Overflow 以不同的方式突出它们。

12
String比string更慢。string拥有更少的像素,消耗的能量也更少。 - Phil B
6
关于@Phil B的评论需要注意的是,这只适用于在 OLED 显示器上使用暗黑模式编程时才有影响。对于液晶显示器或亮色模式,能源消耗是相同的。 - Vapid
5
@VapidLinus 不完全正确,在液晶显示器上,花费能量来隐藏本来亮着的像素,所以更多的暗像素意味着更多的能量消耗!这与CRT显示器相反。因此,在亮度模式下,OLED/CRT上"S"上的像素越多,能量消耗越少;而在液晶显示器上,"S"上的像素越多,能量消耗越大。正如您所述,黑暗模式则相反。尽管测量应该非常精确,并且差异可能会被噪音掩盖。 - fbiazi
2
我认为花费在思考这个问题上的精力比这里节省的能量更多。 - Paŭlo Ebermann

472

有一个区别 - 您不能在使用String之前不使用using System;

更新:

大写字母"S""String"是指.NET Framework基类库中内置字符串数据类型的关键字。它是表示字符序列的引用类型。

另一方面,小写字母"s""string""System.String"类型的别名,这意味着它们本质上是相同的。使用"string"只是一种简写方式来引用"System.String"类型,并且在C#代码中更常用。

在C#中,"String""string"都可以互换使用,您可以使用任何一个来声明字符串类型的变量。

String myString = "Hello World"; // using the String keyword
string myString = "Hello World"; // using the string alias

然而,为了与语言的语法和约定保持一致,建议在C#代码中使用"string"别名。

在这里,您可以阅读更多关于C#字符串的信息。


虽然它是True,但它指出string是System.String的别名,而不是String的别名(https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/types#825-the-string-type)。 - Wouter
不是真的,至少现在不是了(我刚刚检查过!) - Oluwadamilola Adegunwa
1
@OluwadamilolaAdegunwa 这可能是因为您启用了隐式使用构建。 - poizan42

358

前面已经讲过了,但是在反射中你不能使用string,必须使用String


23
我不理解这个答案的含义以及它为什么会被点赞。在反射中,你可以使用 typeof(string)。例如:if (someMethodInfo.ReturnType == typeof(string)) { ... }var p = typeof(string).GetProperty("FirstChar", BindingFlags.NonPublic | BindingFlags.Instance);。那么,在哪里必须使用 String 而非 string?如果你尝试像 Type.GetType("String") 或者 Type.GetType("string") 这样的操作,它们都无法找到类,因为命名空间缺失。如果由于某些“愚蠢”的原因你将类型的 .Name 与区分大小写的 "string" 进行比较,那么你是正确的。 - Jeppe Stig Nielsen
请解释。 - Wouter
我不认为这是真的。编译器将字符串更改为global::System.String,所以没有理由在反射中不能使用字符串。 - Plaje

312

System.String是.NET字符串类 - 在C#中,stringSystem.String的别名 - 因此在使用上它们是相同的。

至于指南,我不会太纠结,只需使用您喜欢的任何一个即可 - 生活中还有更重要的事情,并且代码将是相同的。

如果您发现自己正在构建需要指定所使用整数大小的系统,因此倾向于使用Int16Int32UInt16UInt32等,则使用String可能看起来更自然 - 并且在不同的.net语言之间移动时可能会使事情更容易理解 - 否则我会使用string和int。


248

出于格式化的原因,我更喜欢使用大写的 .NET 类型(而不是别名)。毕竟值类型是合适的对象,.NET 类型与其他对象类型相同颜色。

条件和控制关键字(例如 ifswitchreturn)是小写的,并且默认情况下为深蓝色。我宁愿不让使用和格式产生分歧。

考虑:

String someString; 
string anotherString; 

223

stringString 在所有方面都是相同的(除了大写的 "S")。没有性能上的影响.

在大多数项目中,小写的 string 更受欢迎,因为它可以进行语法高亮。


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