C#中关于字符串的一些特殊点

在C#中,字符串是一个使用比较多的类型,本文会讲到字符串(string)的一些特殊点。

定义

我们先来定义一个字符串类型变量。

string str = "这是一个字符串";

在上面的代码中,我们试用了 stirng 关键字作为类型来定义字符串变量,其实字符串真正的类型为 Stringstring 是作为C#关键字的一个别名,在编码的时候,IDE会给提示,要求我们将 String 修改成 string

我们可以通过反编译来查看 String 的具体定义, String 其实是一个引用类型,派生于 Object 。但是我们在使用的过程中, String 又会表现出值类型的特性(多个变量即使指向了同一个值,在对其中一个变量修改时也不会污染到其他的变量)

public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable, IComparable<string>, IEnumerable<char>, IEquatable<string>
{
}

可以看到 String 类型的定义使用 sealed 关键字,表明 String 类型不可被当作基类继承。 这是因为CLRString 类型做了一些特殊优化,必须防止自定义类型破坏了 CLR 的优化。

这里涉及到 String 类型的一个特性——不变性,即 String 对象一旦创建,就不能再更改.。不变性带来了另一个特性——一致性,即相同的字符串在 CLR 中在表现上同一个对象(其实不是)。这样在使用上, String 类型就和其他的值类型表现一致。不过由于这些特性的存在,所在如果对字符串进行多次修改操作会产生很多临时字符串对象,对性能有影响,所以在很多的库和最佳实践中,都会推荐使用 StringBuilder 来操作。

string str1 = "这是一个字符串";
string str2 = "这是一个字符串";

Console.WriteLine(object.Equals(str1,str2));
// True
Console.WriteLine(object.ReferenceEquals(str1,str2));
// False

可以看到在对象的层面上,两个字符串对象是一致的,这是因为 Equals 比较是靠 GethashCode 方法,而由于 CLR 的特殊优化, String 类型的 GetHashCode 方法会对同样的字符返回一样的哈希值。但是如果我们使用 ReferenceEquals 来比较两个对象的引用还是可以看到其实是两个对象,那么有没有办法做到字符串对象的复用呢?

答案是肯定的,我们只需要使用 Intern 方法即可。

CLR 初始化的时候,会构建一个内部表(暂存池)用来存放 String 对象的引用,而 Intern 方法就是用来访问内部表的,使用 Intern 方法的时候,会先检查内部表中有没有同样的字符串存在,如果有就会直接返回该字符串的引用。所以使用 Intern 方法获得的 String 对象在引用上也是相同的。

string str1 = "这是一个字符串";
string str2 = string.Intern("这是一个字符串");

Console.WriteLine(object.Equals(str1,str2));
// True
Console.WriteLine(object.ReferenceEquals(str1,str2));
// True

当然上面的测试都是在 .net 6的环境中进行的,如果 CLR 的实现不同,对于字符串的优化也有可能不同,甚至在 CLR 中默认开启字符串池,直接把相同值得字符串对象彻底优化成一个引用也是可能的。

发布时间:2024-08-09

其他阅读

Nginx重定向HTTP到HTTPS

HTTP协议以纯文本形式进行数据的交互,数据明文传输,容易被监听,窃取和伪造,HTTPS在HTTP的基础上,使用了TLS/SSL对通信过程进行加密,数据得到了有效的保护,就算被拦截到也无法获取信息,更没法实施中间人攻击。本文将会介绍如何在Nginx中配置HTTP重定向到HTTPS。

Winform中设置控件边框

本文将会介绍在Winform中如何设置控件的边框,可应用于Form和Panel等。

Entity Framework Core链接Oracle的问题

最近使用 Entity Framework Core 来链接 Oracle 11g 数据库,发现很多 LINQ 语句使用起来都会有问题,查看日志输出发现是生成SQL语句无法被 11g 版本执行,好在Oracle官方已经给我们提供了解决方案。

C#中new和override的区别

在C#编程语言中,new 和 override 是两个重要的关键字,它们用于控制类成员方法的行为。在面向对象编程(OOP)中,理解这两个关键字的区别和用法,对于编写清晰、可维护和高效的代码至关重要。

Linux中查看,添加,修改,删除用户和用户组

将用户分组是Linux系统中对用户进行管理及控制访问权限的一种手段。某个用户都属于某个用户组;一个组中可以有多个用户,一个用户也可以属于不同的组。当一个用户同时是多个组中的成员时,登录时所属的为默认组,而其他组称为附加组。本文将会介绍在 Linux 中查看,添加,修改,删除用户和用户组,注意:权限管理非常重要,可能一不小心就导致系统无法登录,请谨慎操作