C#.Net筑基-String字符串超全总结 [深度好文]

news/2025/3/15 23:29:46/文章来源:https://www.cnblogs.com/anding/p/18221262

image.png

字符串是日常编码中最常用的引用类型了,可能没有之一,加上字符串的不可变性、驻留性,很容易产生性能问题,因此必须全面了解一下。


01、字符与字符编码

1.1、字符Char

字符 char 表示为 Unicode字符,在C#中用 UTF-16 编码表示,占用2个字节(16位)大小,字面量用单引号''包裹。

char c = 'A';
Console.WriteLine(char.IsDigit('3'));
Console.WriteLine(char.IsNumber('1'));
Console.WriteLine(char.IsLetter('A'));
Console.WriteLine(char.IsLower('a'));
Console.WriteLine(char.IsUpper('A'));
Console.WriteLine(char.GetUnicodeCategory('A')); //获取字符分类
  • char 是值类型(结构体),以16位整数形式存储,char可隐式转换为int
  • 字符串可以看做是char序列(数组),字符串是引用类型。

image.png

string str = "Hello World";
Console.WriteLine(str[0]);  //H
Console.WriteLine(str[10]); //d
Console.WriteLine(str[0].GetType().Name); //Char

1.2、字符集Unicode与字符编码

一般情况下字符串长度string.Length 就是可见的文本字符数量,但这并不绝对相等。大多数字符都是一个char组成,然而有些字符无法用一个char表示,如表情、不常用字符等,他们会用两个char(4个字节)来表示。

"a".Length.Dump();    //1
"🔊".Length.Dump();  //2
"🚩".Length.Dump();  //2
"⏰".Length.Dump();  //1
"你好".Length.Dump(); //2
"臢".Length.Dump();   //1
$"{(int)'A':X4}".Dump(); //0041
//上面的dump() 是一个扩展方法,作用同Console.WritLine()

Unicode 是国际标准、通用字符集,涵盖了世界上几乎所有的文字、符号,可以满足跨平台、跨语言的文本信息编码。Unicode 有100W+个字符地址空间,地址范围是 0x0000 - 0x10FFFF,每个字符都有自己的编码,目前已分配了大约10W+个。通常使用“U+”后跟一个十六进制数来表示,例如字母A的Unicode码点是U+0041

Unicode 字符集中包含多个分类(平面):其中最常用的就是基本平面,大部分常用字符都在这里面。

  • 🔸基本多文种平面(BMP,Basic Multilingual Plane):Unicode 的BMP区域几乎包含了所有常用的字符,如几十种主流语言,及30000+的汉字,BMP区域的字符都只需要1个char(2个字节)表示。
  • 🔸辅助平面(SMP):包含其他不常使用的字符,如一些历史文字、音乐符号、数学符号和表情符号等。该区域大多用两个char(4个字节)表示一个符号。

image.png

Unicode 是一种字符集,而实际在计算机上存储时需要用一个确定的编码方案,常见的就是UTF-8、UTF-16、UTF32。

  • UTF-16:2个字节表示BMP中的字符,其他字符会需要4个字节,C#、Java语言内部就是使用的UTF-16来表示的字符串。
  • UTF-8:变长编码,使用1到4个字节来表示一个Unicode字符,在互联网使用广泛。特别是存储 ASCII 为主的内容时,变长编码可以显著节约存储空间。

📢ASCII 字符集只包含 128个 基础字符,涵盖键盘上的字母、数字、常用符号。Unicode 是包含 ASCII字符集的,最前面128 个字符就是。在UTF-8编码中 ASCII字符只需要1个字节。


02、String基础

字符串 string 是一个不可变(不可修改)的字符序列(数组),为引用类型,字面量用双引号""包裹。

string s1 = "sam";
string s2 = new string('1',5);//11111
Console.WriteLine(s2[0]); //像数组一样操作字符串中的字符
string s3 = "";
string s4 = string.Empty; //效果同上
//相等比较
object s1= "Hello".Substring(0,2);
object s2 = "Hello".Substring(0,2);	
(s1==s2).Dump();        //False
(s1.Equals(s2)).Dump(); //True
  • 字符串是引用类型,因此可以用null表示,不过一般空字符建议用string.Empty(或"")表示。
  • 字符串可以当做 字符数组一样操作,只是不能修改。
  • 字符串的相等为值比较,只要字符序列相同即可。例外情况请是如果用object==比较,只会比较引用地址。

image.png

🚩 字符串在存储、转换为字节码时需指定编码,一般默认为 UTF-8,这是广泛使用的编码类型,更节省空间。

2.1、字符串常用API

属性 特点/说明
Length 字符串中字符数量
索引器[int index] 索引器,用索引获取字符,不可修改
🔸方法 特点/说明
StartsWith、EndsWith(String) 判断开头、结尾是否匹配,"Hello".StartsWith("He")
Equals(String) 比较字符串是否相同
IndexOf() 查找指定字符(串)的索引位置,从后往前查找 LastIndexOf
Insert(Int32, String) 指定位置插入字符串,‼️返回新字符串!
PadLeft(Int32) 指定字符宽度(数量)对齐,左侧填充,‼️返回新字符串!右侧填充 PadRight(Int32)
Remove(Int32, Int32) 删除指定位置、长度的字符,‼️返回新字符串!
Replace(String, String) 替换指定内容的字符(串),‼️返回新字符串!
Substring(Int32, Int32) 截取指定位置、长度的字符串,‼️返回新字符串!
ToLower()、ToUpper() 返回小写、大写形式的字符串,‼️返回新字符串!
Trim() 裁剪掉前后空格,‼️返回新字符串!有多个配套方法 TrimEnd、TrimStart
Split(char) 按分隔符分割字符串为多个子串,比较常用,不过性能不好,建议用Span代替。
🔸静态方法 特点/说明
Empty 获取一个空字符串(同""
Compare(String, String) 比较两个字符串,有很多重载,返回一个整数,0表示相同。
Concat (params string?[]) 连接多个字符串,返回一个新的字符串,有很多重载,是比较基础的字符串连接函数。
Equals(str, StringComparison) 比较字符串是否相同,可指定比较规则 StringComparison
Format(String, Object[]) 字符串格式化,远古时期常用的字符串格式化方式,现在多实用$插值
string Intern(String) 获取“内部”字符串,先检查字符串池中是否存在,有则返回其引用,没有则添加并返回
string? IsInterned(String) 判断是否在字符串池中,存在则返回其引用,没有则返回null
IsNullOrEmpty(String) 判断指定的字符串是否 null 、空字符""/String.Empty,返回bool
IsNullOrWhiteSpace(String) 判断指定的字符串是否 null 、空字符""/String.Empty、空格字符,返回bool
Join(Char, String[]) 用分隔符连接一个数组为一个字符串

2.2、字符串的不变性、驻留性

字符串是一种有一点点特别的引用类型,因为其不变性,所以在参数传递时有点像值类型。

  • 🔸不变性:字符串一经创建,值不可变。对字符串的各种修改操作都会创建新的字符串对象,这一点要非常重视,应尽量避免,较少不必要的内存开销。
  • 🔸驻留性:运行时将字符串值存储在“驻留池(字符串池)”中,相同值的字符串都复用同一地址。

不变性、驻留性 是.Net对string 的性能优化,提升字符串的处理性能。如下示例中,s1、s2字符串是同一个引用。

string s1 = "hello";
string s2 = "hello";
Console.WriteLine(s1 == s2);                      //True
Console.WriteLine(s1.Equals(s2));                 //True
Console.WriteLine(Object.ReferenceEquals(s1,s2)); //True

当然不是所有字符串都会驻留,那样驻留池不就撑爆了吗!一般只有两种情况下字符串会被驻留:

  • 字面量的字符串,这在编译阶段就能确定的“字符串常量值”。相同值的字符串只会分配一次,后面的就会复用同一引用。
  • 通过 string.Intern(string) 方法主动添加驻留池。

image.png

string st1 = "123" + "abc";
string st2 = "123abc";
string st3 = st2.Substring(0,3);

看看上面代码生成的IL代码:

image.png

  • 常量的字符串"123" + "abc"连接被编译器优化了。
  • 常量字符串使用指令“ldstr”加载的到栈,该指令会先查看驻留池中是否已存在,如果已存在则直接返回已有字符串对象的地址,否则就加入。

image.png

驻留的字符串(字符串池)在托管堆上存储,大家共享,内部其实是一个哈希表,存储被驻留的字符串和其内存地址。驻留池生命周期同进程,并不受GC管理,因此无法被回收。因此需要注意:

  • lock锁不能用string,避免使用同一个锁(字符串引用)。
  • 避免创建字面量的大字符串,会常住内存无法释放,当然也不要滥用string.Intern(string) 方法。

2.3、字符串的查找、比较

string 的 比较字符串 是默认包含文化和区分大小写的顺序比较,C#内置的一个字符串比较规则(枚举)StringComparison,可设置比较规则。在很多内置方法中使用,包括 String.Equals、String.Compare、String.IndexOf 和 String.StartsWith等。

📢 微软官方建议在使用上述字符串比较方法中明确指定 StringComparison 参数值,而不是默认的比较规则。

public enum StringComparison
{CurrentCulture,CurrentCultureIgnoreCase,InvariantCulture,InvariantCultureIgnoreCase,Ordinal,OrdinalIgnoreCase
}
void Main()
{string.Equals("ABC","abc",StringComparison.Ordinal);           //Faslestring.Equals("ABC","abc",StringComparison.OrdinalIgnoreCase); //Truestring.Compare("ABC","abc",StringComparison.Ordinal);          //-32string.Compare("ABC","abc",StringComparison.OrdinalIgnoreCase);//0
}
枚举值 说明
CurrentCulture 本地语言区域规则,适用于给用户显示的内容
CurrentCultureIgnoreCase 同上+忽略大小写
InvariantCulture 固定语言区域,适用于存储的数据
InvariantCultureIgnoreCase 同上+忽略大小写
Ordinal 二进制值顺序比较字符串,比较快⚡
OrdinalIgnoreCase 同上+忽略大小写

如果单纯从性能角度考虑,考虑语言文化的字符串比较其实比较慢,来测试对比一下。测试代码:

string s1 = "hellohellohellohello";
string s2 = "helloHelloHelloHello";public bool Equals() => s1.Equals(s2);//Falsepublic bool Equals_CurrentCulture() => s1.Equals(s2,StringComparison.CurrentCulture);//False
public bool Equals_CurrentCultureIgnoreCase() => s1.Equals(s2,StringComparison.CurrentCultureIgnoreCase);//True
public bool Equals_InvariantCulture() => s1.Equals(s2,StringComparison.InvariantCulture);//False
public bool Equals_InvariantCultureIgnoreCase() => s1.Equals(s2,StringComparison.InvariantCultureIgnoreCase);//True
public bool Equals_Ordinal() => s1.Equals(s2,StringComparison.Ordinal);//False
public bool Equals_OrdinalIgnoreCase() => s1.Equals(s2,StringComparison.OrdinalIgnoreCase);//Truepublic bool Equals_Span() => s1.AsSpan() == s2.AsSpan();//False
  • 上面7个方法 分别测试了Equals的默认版本、及带参 StringComparison 的不同比较规则的性能。
  • 最后加了一个使用Span 的相等比较,更多关于Span的资料查看《高性能的Span、Memory》。

image.png

🚩测结结论

  • Span最快,其次无参Equals()版本、Ordinal,他们都是只比较二进制值,不考虑文化信息。
  • 个人理解,如果不考虑一些比较特别的语言(如瑞典语、土耳其语、 阿塞拜疆语等),只是针对英文、中文的字符串,一般不用考虑文化语义。
  • Equals()默认是不考虑文化语义的字符值比较,但有些比较方法就不一定能了,比如StartsWithCompare 默认的是带文化语义的CurrentCulture规则,因此推荐主动配置 StringComparison 参数。

2.4、字符串转义\

转义字符:反斜杠“\”

转义序列 字符名称 Unicode 编码
\' 单引号 0x0027
\" 双引号 0x0022
\0 null 0x0000
\b Backspace 0x0008
\f 换页 0x000C
\n 换行 0x000A
\r 回车 0x000D
\t 水平制表符 0x0009

image.png


03、🚩字符串连接的8种方式

字符串连接(组装)的使用是非常频繁的,.Net中提供了多种姿势来实现,各有特点。

连接方法 示例/说明
直接相加 "hello"+str,其实编译后为 string.Concat ("hello", str)
连接函数:String.Concat() 字符串相加一般就是被编译为调用String.Concat()方法,有很多重载,支持任意多个参数
集合连接函数:String.Join() 将(集合)参数连接为一个字符串,string.Join('-',1,2,3); //1-2-3
格式化:String.Format() 传统的字符串格式化手艺,string.Format("name:{0},age:{1}",str,18)
$ 字符串插值 用花括号{var}引用变量、表达式,强大、方便,$"Hello {name} !"
@逐字文本字面量 支持转义符号、换行符,常用于文件路径、多行字符:@$"C:\\Users\\{name}\\Downloads"
"""原始字符串字面量 C# 11,三个双冒号包围,支持多行文本的原始字面量。
StringBuilder 当处理大量字符串连接操作时,推荐使用StringBuilder,效果更优。

字面量字符串的相加会被编译器优化,直接合并为一个字符串。

var str1 = "Hello " + "world" + " !";
var str2 = DateTime.Now.Year + "年" + DateTime.Now.Month + "月";//编译后的代码:
string str1 = "Hello world !";
string str2 = string.Concat (DateTime.Now.Year.ToString (), "年", DateTime.Now.Month.ToString (), "月");

3.1、字符串格式化 String.Format

String.Format 方法是早期比较常用的字符串组织方式,后来$字符串插值 问世后就逐步被打入冷宫了。

string.Format("{0}+{1} = {2}",1,2,3);  //1+2 = 3
string.Format("Hello {0},{0}","sam");  //Hello sam,sam
String.Format("It is now {0:yyyy-MM-dd} at {0:hh:mm:ss}", DateTime.Now); //It is now 2024-01-17 at 10:56:33
String.Format("买了{0}个桔子,共花了{1:C2}。", 4,25.445); //买了4个桔子,共花了¥25.45。

基本语法规则就是用 {index}来占位,在后面的参数中给出值。

  • 索引位置从0开始,必须连续递增,可以重复。
  • 索引的位置对应后面参数的顺序位置,必须对应,参数不能少(抛出异常),可以多。
  • 字符串格式规则参考后文《字符串格式总结》。

3.2、$字符串插值

字符串插值的格式:$"{<interpolationExpression>}",大括号中可以是一个变量,一个(简单)表达式语句,还支持设置格式。功能强大、使用方便,老人孩子都爱用!

  • {}字符转义,用两个{{}}即可,如果只有一边,则用单引号'{{',即输出为{
  • 使用三元运算符?表达式,用括号包起来即可,因为“:”在插值字符串中有特殊含义,即格式化。
  • 字符串格式规则参考后文《字符串格式总结》。
var name = "sam";
Console.WriteLine($"Hello {name}!");  //Hello sam!
Console.WriteLine($"日期:{DateTime.Now.AddDays(1):yyyy-MM-dd HH:mm:ss}");  //日期:2024-01-18 23:21:55!
Console.WriteLine($"ThreadID:{Environment.CurrentManagedThreadId:0000}");  //ThreadID:0001
Console.WriteLine($"Length:{name.Length}");  //Length:3
Console.WriteLine($"Length:{(name.Length>3?"OK":"Error")}");  //Length:Error

3.3、@字符串支持任意字符

@标记的字符串为字面量字符串 ,不需要使用转义字符了,可搭配$字符串插值使用。文件路径地址都会用到@,两个冒号表示一个冒号,@"a""b" ==a"b

var path= @"D:\GApp\LINQPad 8\x64";
var file = $@"D:\GApp\LINQPad 8\x64\{DateTime.Now:D}";
var maxText = @"Hi All:第一行换行";

3.4、👍🏻StringBuilder

StringBuilder 字符串修理工程师,顾名思义,就是专门用来组装字符串的,可以看做是一个可变长字符集合。适用于把很多字符串组装到一起的场景,避免了大量临时字符串对象的创建,可显著提升性能。

var sb = new StringBuilder(100);
sb.Append("sam");
sb[0] = 'F';  //Fam
sb.AppendLine("age");
sb.Append("age").Append(Environment.NewLine); //效果同上
sb.Insert(2,"---");
sb.Replace("age","Age");var result = sb.ToString(); //获取结果
属性 特点/说明
Capacity 获取、设置字符容量(实际占用内存),默认16,当内容增多容量不足时,会自动扩容。
MaxCapacity 获取最大容量,20亿字符
Length 实际字符内容的长度,可赋值,设置0则清空已有字符内容,但并不影响 Capacity。
Chars[Int32] 索引器,可获取、设置字符
🔸方法 特点/说明
StringBuilder(Int32) 构造函数,参数指定初始容量capacity
Append(value) 追加字符,很多重载版本,类似还有AppendFormat、AppendJoin
AppendLine 追加字符后,再追加一个换行符
Insert (int index, value) 指定位置插入字符内容
Replace(Char, Char) 查找替换字符(字符串)内容,会替换所有找到的字符内容
ToString() 将 StringBuilder 输出为一个字符串,一般是StringBuilder的命运终点。
  • 各种Append方法都返回自身,可用来链式编程。
  • StringBuilder 默认容量为16,内部有一个char数组m_ChunkChars(缓冲区)来存储字符内容,如下StringBuilder构造函数源码:
public StringBuilder()
{m_MaxCapacity = int.MaxValue;m_ChunkChars = new char[16];
}
  • 当不断追加字符串,容量不足会自动扩容,扩容的过程其实就是创建更大的字符数组(容量翻倍),把原来的值拷贝过来,这个过程会涉及数组对象创建、内存拷贝。

📢 一般使用StringBuilder 建议尽量给一个合理的默认容量大小,尽量避免、减少频繁的扩容。


04、🚩字符串格式化大全

📢字符串格式语法:{index/interpolationExpression [,alignment][:formatString]}

  • ,alignment可选,设置字符串的对齐长度,如果位数不够则空格补齐,正数部补左边,负数补右边。
  • :formatString指定格式规则。一次只能指定一个格式规则,可和,alignment共存。
//,alignment 示例
var name = "sam";
$"name:{name,6}.";    //字符长度6,前面补齐空格 //name:   sam.
$"name:{name,-6}.";   //字符长度6,后面补齐空格 //name:sam   .
"1123+1 = {(1223+1),6:#,#.##}";                //1123+1 =  1,224
string.Format("1123+1 = {0,6:#,#.##}",1223+1); //1123+1 =  1,224

4.1、数值格式

🚩标准数值格式

🔸数值格式 说明
E3/e3 科学计数法(指数),数字"3"为小数精度,$"{12345.2:E3}" //1.235E+004,E+4表示10的4次方;如果是E-4则表示为小数(除以10的四次方) 1E-4 = 0.0001
F4 定点格式,小数精度为"4",位数不够后面补0,支持所有数值类型,$"{123.22F:F4}" //123.2200
G4 定点格式F+指数E的结合版,最多"4"个有效数字,超过就用科学计数法。"{123:G2}" //1.2E+02,$"{123:G4}" //123
C3 货币格式(支持千分位),数字“3”为小数位数,$"{123.346:C2}" //¥123.35
P2 百分比格式,数字乘以100后转换为百分数,数字“2”为小数位数,$"{0.2:P2}" //20.00%
N6 数字格式化(支持千分位),小数位数为6,不够后面补0,$"{123:N6}" //123.000000
D6 整数定长格式,不够前面补0,只支持整数,$"{123:D6}" //000123
B 输出为二进制格式,仅支持整数+.Net8,精度为字符串位数,不够补0,$"{123:B}" //1111011
X/x 输出为十六进制格式,仅支持整数+,精度为字符串位数,不够补0,$"{12:X4}" //000C

🚩自定义的数值格式

🔸数值格式符号 说明
# 数字占位符,不强制占位,$"{123:#,###.##}" //123
0 数字(0)占位符,强制占位,不够补0。$"{123:0000.00}" //0123.00
. 小数点,
, 千分位,
, 倍数符号,也是逗号,在末尾、小数点前为倍数符号,除以1000,可多个。$"{12000:#,}" //12
% 百分数,乘一百+%,$"{0.2:00.00%}" //20.00%
E/e 指数(科学计数),$"{10.1234:0.00e0}" //1.01e1;$"{0.01234:0.00e0}" //1.23e-2
\\ 转义字符,

📢热知识:小数格式化截断时都会四舍五入,(int)double 强转换是直接截断整数部分,相当于向下取整。
🔊冷知识:土耳其文化中的小数点为“逗号”,而非“点”。

4.2、日期时间格式

🔸日期格式-自定义 说明(DateTimeDateTimeOffset
yyyy 年份,yyyy //2024,yy //24
MM 2位数的月份,1个M就不会补0 了,3/4个M为月份名称。M //4,MM //04,MMM //4月,MMMM //四月
dd 2位数的日,3/4个d为星期。d //8,dd //08,ddd //周一,dddd //星期一
HH 2位数的小时(24小时制)
hh 2位数的小时(12小时制)
mm 2位数的分钟
ss 2位数的秒
f 为1/10秒单位,ff为1/100秒单位,以此类推,fff就表示毫秒
tt AM/PM 指示符
组合使用 以上可组合使用,可穿插任意字符,$"{DateTime.Now:yyyy年MM月dd日 HH:mm:ss}"
🔸日期格式-简写 说明
D、d D长日期,d短日期,$"{DateTime.Now:D}" //2024年1月18日
F、f 完整日期/时间模式,F长时间,f短时间,$"{DateTime.Now:F}" //2024年1月18日 22:45:34
T、t T长时间,t短时间,$"{DateTime.Now:T}" //22:45:42
M/m 月日模式,$"{DateTime.Now:M}" //1月18日
Y/y 年月模式,$"{DateTime.Now:Y}" //2024年1月

4.3、其他格式

🔸枚举格式 说明
G/g,F/f 枚举的字符串名称,其中F用于Flags,$"{UType.User:G}" //User
D/d 十进制枚举值,$"{UType.User:D}" //2
X/x 十六进制枚举值,$"{UType.User:X}" //00000002
🔸其他 说明
IFormattable 自定义的格式化接口,使用自定义的 IFormatProvider 来实现格式化输出ToString()
NumberStyles 用于解析数字符串(Parse)时指定的解析格式
DateTimeStyles 同上,用于时间日期的解析

🚩格式MSDN参考资料

  • 所有整型和浮点类型。 (请参阅 标准数字格式字符串 和 自定义数值格式字符串。)
  • DateTime 和 DateTimeOffset。 (请参阅 标准日期和时间格式字符串 和 自定义日期和时间格式字符串。)
  • 所有枚举类型。 (请参阅 枚举格式字符串.)
  • TimeSpan 值。 (请参阅 标准 TimeSpan 格式字符串 和 自定义 TimeSpan 格式字符串。)
  • GUID。 (请参阅 Guid.ToString(String) 方法。)

06、高性能字符串实践

提高string处理性能的核心就是:尽量减少临时字符串对象的创建

  • 高频常用字符串(非字面量)可考虑主动驻留字符串,string.Intern(name)
  • 字符串的比较、查找,优先用Span,或者尽量使用无文化语义的比较StringComparison.Ordinal
  • 大量字符串连接使用StringBuilder,且尽量给定一个合适的容量大小,避免频繁的扩容。
  • 少量字符串连接用字符串插值即可,创建StringBuilder也是有成本的。
  • 如果有大量StringBuilder 的使用,可以考虑用StringBuilderCache,或池化StringBuilder。

6.1、比较字符串

  • 字符串查找、拆分字符串、解析字符串,推荐使用Span,参考《高性能的Span、Memory》。
  • 查找、比较字符串,尽量指定 StringComparisonOrdinalOrdinalIgnoreCase,采用无文化特征的比较性能更快。
string str1="a",str2 = "b";
//这种方式会产生新的字符串,不推荐
if(str1.ToLower() == str2.ToLower()){} 
//推荐写法
if(string.Compare(str1, str2, true)==0){} 
if(string.Equals(str1,str2,StringComparison.Ordinal)){}

image.png

6.2、字符串真的不能修改吗?

字符串其实也是可以修改的,当然是用非常规手段。

  • ref获取指定字符的引用地址(指针地址)。
static void Main(string[] args)
{var str1 = "hello";var str2 = "hello";//修改第0位ref var c1 = ref MemoryMarshal.GetReference<char>(str1);c1 = 'H';//修改第一位ref var c2 = ref MemoryMarshal.GetReference<char>(str1.AsSpan(1));c2 = 'E';Console.WriteLine(str1);//输出:HElloConsole.WriteLine(str2);//输出:HEllo
}
  • 直接使用指针修改字符值。
void Main()
{var str1 = "hello";var str2 = "hello";unsafe{fixed (char* c = str2){c[0] = 'H';c[1] = 'E';}}Console.WriteLine(str1); //HElloConsole.WriteLine(str2); //HEllo
}

参考资料

  • C# 文档
  • 《C#8.0 In a Nutshell》
  • .NET面试题解析(03)-string与字符串操作
  • .NET 中的字符编码

©️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/720795.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

类的继承,接口的使用

1-知识点,题量,难度总结 1.this与super的区分与使用,如何正确使用多态(用父类类型创建子类对象,并调用子类中重写父类中的抽象方法)(在大作业5中的第二道修改学生信息中)(第三道中父类向下转型,另外还有子类向上转型)。 2接口的使用,多态的具体体现(例如在第一次家…

The University of Sydney

QS大学排名QS世界大学排名 QS大学学科排名 QS亚洲大学排名 QS商科硕士排名 QS就业竞争力排名 QS全球MBA排名软科ARWU大学排名 泰晤士大学排名 USNEWS大学排名 金融时报(FT)商学院排名 EduRank大学排名 CWUR世界大学排名 武书连大学排名 校友会大学排名 登录 去除广告?下载大…

QS世界大学排名 2025

大学排名 发现 展会活动 留学准备 申请 职业发展中文免费注册排名方法什么是QS之星? QS世界大学排名 2025通过2025年的QS世界大学排名,发现世界顶尖大学。展开In partnership with 排名榜单 排名指标 年份 2025…

chrome浏览器被360导航劫持解决办法

右键单击桌面浏览器图标 点击属性 修改目标,去点360的导航url,ok

读AI未来进行式笔记04数字医疗与机器人

读AI未来进行式笔记04数字医疗与机器人1. 数字医疗 1.1. 20世纪的“现代医学”得益于史无前例的科学突破,使得医疗的方方面面都得到改善,让人类预期寿命从1900年的31岁提高到2017年的72岁 1.2. 现有的医疗数据库和流程将实现数字化 1.2.1. 患…

linux启动

1. BIOS BIOS 代表基本输入/输出系统。简单来说,BIOS 会加载并执行主引导记录 (MBR) 引导加载程序。 首次打开计算机时,BIOS 首先对 HDD 或 SSD 执行一些完整性检查。 然后,BIOS 搜索、加载并执行引导加载程序,该程序可以在主引导记录 (MBR) 中找到。MBR 有时位于 USB 记忆…

Grid布局

目录Grid布局概述Grid 布局和 flex 布局网格布局的属性容器和项目网格轨道网格线 Grid布局 概述 Grid 布局即网格布局,目前css布局方案中,网格布局可以算得上是最强大的布局方案了。它可以将网页分为一个个网格,然后利用这些网格组合做出各种各样的布局。比较擅长将一个页面划…

产品功能架构图

产品功能架构图的绘制可以帮助团队更清晰地了解产品的功能结构,有助于沟通和协作。它也可以用于指导产品开发过程,帮助开发团队更好地理解产品需求和功能实现方式。现实情况是,很多产品初期都是在公司阶段,非常的模糊,这个时候boss让你画个产品架构图,你很抓瞎,大千UI工…

GPU与DSA架构分析

GPU与DSA架构分析GPU、GPGPU、DSA、FPGA、ASIC等AI芯片特性及对比GPUGPU(Graphics Processing Unit,图形处理器)是一种专门用于处理图形和图像的处理器。它是计算机的重要组成部分,主要用于加速图形和图像的处理和渲染。与传统的中央处理器(CPU)相比,GPU具有更多的并行处…

k8s组件和网络插件挂掉,演示已有的pod是否正常运行

环境 03 master ,05 06是node[root@mcwk8s03 mcwtest]# kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME mcwk8s05 Ready <none> 58…

W801单片机入门开发环境设置

W801单片机入门开发环境设置开发软件下载 烧录工具和SDK 在 WinnerMicro的网站 https://www.winnermicro.com/html/1/156/158/558.htmlch340 USB串口驱动 如果没有的话 https://www.onlinedown.net/soft/1164748.htm开发用的IDE CDK 在平头哥的网站 https://www.xrvm.cn/soft-t…

嵌入式笔记5.1 定时器详解

目录一、SysTick——系统节拍定时器1. 信息介绍2. 功能介绍(工作模式)3. 寄存器介绍4. 使用方式5. 其他信息二、RTC——实时时钟1. 信息介绍2. 寄存器详解0. 寄存器地址1. RTC 时间寄存器(RTC_TR)2. RTC 日期寄存器(RTC_DR)3. RTC 亚秒寄存器(RTC_SSR)4. RTC 初始化控制…