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
其他阅读

解决ssh登录后闲置一段时间断开

最新新买了一台服务器,使用 ssh 登录之后发现一段时间没有输入就会自动断开,这里记录一下解决方法。

查看原文

WPF中开启虚拟化提高性能

WPF(Windows Presentation Foundation)是一个强大的框架,它能创建高度响应和美观的桌面应用程序。然而,当处理大量数据时,性能问题可能变得显著。为了解决这些问题,我们可以利用虚拟化来提升WPF应用的性能。

查看原文

网页上通过超链接直接打开PC应用

有时候我们会发现有些网页可以直接打开本地应用,比如在百度网盘网页版下载文件时,会自动打开本地的百度网盘软件。Visual Studio Code打开浏览器认证后也会转到本地引用,Unity官网打开本地的Unity Hub应用进行Unity的下载和更新等。

查看原文

Angular中制作一个按钮组件

本文将会介绍如何在Angular中制作一个按钮组件,直接在原生按钮上添加特性即可使用,还提供多种颜色方便切换。

查看原文

Angular使用路由复用实现单页多窗(Tab)

我们在开发后台管理系统时,一个很重要的需求就是多窗口编辑,来回切换使用。一种思路是使用iframe来记录多个多页面展示,本文通过Angular路由复用来实现这一需求。

查看原文