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

WPF中开启虚拟化提高性能

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

查看原文

浅析web前端中的MVC模式

MVC是常见的软件架构设计模式,它通过分离关注点改进代码的组织方式。区别于软件设计模式,只是为了解决问题总结出的抽象方法,一种架构模式种往往会用到多种设计模式。

查看原文

vscode Material Design Theme

Material Design Theme 是由猪头少年(scung-cn)开发的一套基于 Material Design 设计语言的 Visual Studio Code 主题插件,可以在扩展市场上直接下载安装。

查看原文

管道技术——中间件的灵魂

在现代Web开发中,中间件技术使用越来越广泛,本文带大家了解中间件的基础,同时也是中间件的灵魂所在,管道技术。在C#中,依赖于委托,我们可以很容易就实现一个中间件管道。所以在阅读本文前,请确保你已经学会了什么是委托,包括但不限于Delegate,Action,Func。除此之外,本文还会使用到反射相关知识,请确保你已经学会了什么是反射。

查看原文

个人简介

你好,我是猪头少年,是一名定居在云南的软件工程师,主要的开发语言为 C#JavaScript,涉及 ASP.NET CoreWPFAngularUnity 以及 Babylon.js。平时喜欢自驾出游。欢迎大家联系我。

查看原文