为什么 .NET 字符串是不可变的? [复制]

2023-11-23

众所周知,String是不可变的。 String不可变的原因是什么以及引入字符串生成器类是可变的?


  1. 不可变类型的实例本质上是线程安全的,因为没有线程可以修改它,所以消除了线程以干扰另一个线程的方式修改它的风险(引用本身是另一回事)。
  2. 类似地,别名不能产生更改(如果 x 和 y 都引用同一对象,则对 x 的更改必然对 y 进行更改)这一事实允许进行相当大的编译器优化。
  3. 节省内存的优化也是可能的。实习和原子化是最明显的例子,尽管我们可以做相同原理的其他版本。我曾经通过比较不可变对象并替换对重复项的引用,使它们都指向同一个实例,节省了大约半 GB 的内存(这很耗时,但为了节省大量内存而需要额外启动一分钟)在相关案例中性能获胜)。对于可变对象,这是无法完成的。
  4. 将不可变类型作为方法传递给参数不会产生任何副作用,除非它是out or ref(因为这改变了引用,而不是对象)。因此,程序员知道如果string x = "abc"在方法的开头,并且方法体中不会改变,那么x == "abc"在该方法的末尾。
  5. 从概念上讲,语义更像是值类型;特别是,平等是基于国家而不是身份。这意味着"abc" == "ab" + "c"。虽然这不需要不变性,但事实上,对此类字符串的引用在其整个生命周期中始终等于“abc”(这确实需要不变性),这使得在保持与先前值的相等性至关重要的情况下用作键,更容易确保正确性of (字符串确实常用作键)。
  6. 从概念上讲,不可变更有意义。如果我们在圣诞节后加一个月,我们并没有改变圣诞节,而是在一月下旬制定了一个新的日期。因此这是有道理的Christmas.AddMonths(1)产生一个新的DateTime而不是改变一个可变的。 (另一个例子,如果我作为一个可变对象更改了我的名字,改变的是我正在使用的名字,“Jon”保持不变,其他 Jons 将不受影响。
  7. 复制快速而简单,只需创建一个克隆return this。由于副本无论如何都无法更改,因此假装某些内容是其自己的副本是安全的。
  8. [编辑,我忘了这个]。内部状态可以在对象之间安全地共享。例如,如果您正在实现由数组、起始索引和计数支持的列表,那么创建子范围最昂贵的部分将是复制对象。但是,如果它是不可变的,则子范围对象可以引用同一数组,只需更改起始索引和计数,并使用very施工时间发生显着变化。

总而言之,对于那些不以变化为目的的对象来说,不可变可能有很多优点。主要缺点是需要额外的构造,尽管即使在这里它也经常被夸大(记住,在 StringBuilder 变得比等效的串联系列及其固有构造更高效之前,您必须执行多次追加)。

如果可变性是对象目的的一部分(谁希望由工资永远不会改变的 Employee 对象建模),这将是一个缺点,尽管有时即使这样它也可能很有用(在许多网络和其他无状态对象中)应用程序中,执行读取操作的代码与执行更新的代码是分开的,并且使用不同的对象可能是自然的 - 我不会使对象不可变,然后强制该模式,但如果我已经有了该模式,我可能会创建“读取”对象对于性能和正确性保证增益来说是不可变的)。

写时复制是一个中间立场。这里“真实”类持有对“状态”类的引用。状态类在复制操作中共享,但如果更改状态,则会创建状态类的新副本。这在 C++ 中比在 C# 中更常使用,这就是为什么 std:string 享有不可变类型的一些(但不是全部)优点,同时保持可变。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 .NET 字符串是不可变的? [复制] 的相关文章

随机推荐

  • 如何使 SET XACT_ABORT ON 回滚事务?

    基于书籍 在线文档SET XACT ABORT ON 我的印象是 如果 T SQL 语句引发运行时错误 则整个事务将终止并回滚 Remarks 当 SET XACT ABORT 为 ON 时 如果 Transact SQL 语句引发运行时错
  • LINQ 在查询中插入 'ESCAPE N'~'

    当我检查 Linq 发出的 SQL 查询时 我注意到它在执行 LIKE 命令时放置了一个 ESCAPE N 我该如何摆脱这个 看起来查询花费的时间是 SQL 中转义符的两倍 这是 LINQ var SearchPhrase xyz var
  • 如何使用 perl cd 进入目录?

    我正在尝试以下 系统 cd目录文件夹 但它失败了 我也尝试系统 退出 离开终端 但它失败了 Code chdir path to dir or die Perldoc chdir EXPR chdir FILEHANDLE chdir DI
  • 用于解析 SQL 参数的正则表达式

    如果我有一个查询 例如SELECT from authors where name name param 是否有正则表达式来解析参数名称 特别是 name param Thanks 这很棘手 因为参数也可能出现在带引号的字符串内 SELEC
  • 重新启动程序未提升

    由于某种原因 我的 C 程序需要以提升的权限重新启动 我使用以下代码来实现它 private static void RestartForPermissionsFix ProcessStartInfo processInfo new Pro
  • 如何加密密码列

    我在 SQL Server 2008 r2 中有用户表 目前还没有加密任何内容 但我想至少对密码进行加密 直到应用程序准备就绪 可以更好地处理这个问题 我可以这样做吗 如何做 手动对密码进行加密 您可以使用 SQL Server 加密列 请
  • 更改部署目标后无法再将应用程序模块导入到单元测试中

    为了在我的快速单元测试中对我的主应用程序目标的公共类进行单元测试 我必须在我的测试中导入我的主应用程序模块 如下所示 import MyAppModuleName 在我将部署目标从 7 0 更改为 8 4 之前 这一切都很好 现在构建和运行
  • 取出特定命名空间的所有类

    有没有办法从特定名称空间获取对象 也许与System Reflections 我想从类型中获取所有对象ITestType在命名空间中Test TestTypes作为对象 以便我有一个实例列表TestType1 TestType2 TestT
  • iOS 获取键盘窗口

    所以在 iOS 7 中我总是得到这样的键盘窗口 UIView keyboardView UIWindow tempWindow Because we cant get access to the UIKeyboard throught th
  • Steam Web API 获取 CS:GO 库存

    好吧 所以我一直在互联网上寻找这个 我发现当你想获得某人的蒸汽库存时 你可以使用这个 http api steampowered com IEconItems appid GetPlayerItems v0001 key apikey st
  • 使用 Intellij 13.1.3 的 Android 渲染问题

    在 IntelliJ 13 1 3 中查看 Android 应用程序中 唯一 活动的预览时 出现以下错误 渲染问题 此版本的渲染库比您的 IntelliJ IDEA 版本更新 请更新 IntelliJ IDEA 对我哪里出错有什么想法吗 这
  • 外部触发 Raphael 事件

    我的应用程序使用 Rapha l 将一组对象拖放到页面上 每个对象都有一个click处理程序绑定 使用通过 JSON 加载时附加到对象的数据 一切正常 我现在尝试使用 Cucumber 添加一些测试覆盖率 是的 我知道我应该首先构建测试 我
  • 避免在 Android 中方向改变时使用 asynctask 重新加载 Activity

    在android中 当用户改变方向时 如何避免在活动中使用asynctask类重新加载活动 有人可以举个例子吗 请关闭配置更改作为最后的手段 你的应用程序must发生这种情况时可以正常工作 如果您关闭方向配置更改 因为它会中断 您的应用程序
  • Angular 2 路由器 - 命名出口

    文档不是很好 但我试图在同一页面 路由上有不同的路由器出口 我的 app component html 中有这个
  • mvccontrib 测试助手并验证 http post 路由和参数

    在我的 Asp net MVC 应用程序中 我在控制器上有两种方法 一种用于用户第一次到达视图时 另一种用于用户在所述视图上提交表单时 public ActionResult Foo AcceptVerbs HttpVerbs Post p
  • 通过标签名称获取多个元素并在循环中检查元素标签以回显它

    这是有效的代码示例 doc gt loadHTML article header imgs doc gt getElementsByTagName img foreach imgs as img imgs取自 doc带有标签名称的元素img
  • 为什么某些 .onion 站点会收到“SOCKS 连接失败。规则集不允许连接”的信息?

    我正在尝试使用 Node 和ocks5 https 客户端 由于某种原因 某些 Tor 隐藏服务 onion 站点返回时出现连接错误 例如 连接到 DuckDuckGo 3g2upl4pq6kufc4m onion 工作并返回 HTML 但
  • 将 float[] 转换为 byte[] 再次转换为 float[]

    所以我在这里想做的是得到一个float 将其转换为byte 将其作为数据报包通过网络发送 然后将其转换回byte 在接收终端 现在我知道我可以转换float to byte 通过使用getBytes 方法 但我不知道如何反转转换 我想你想利
  • 将模板化基类转换运算符引入派生范围

    我有一个基类 它定义了约束模板化转换运算符 struct base template
  • 为什么 .NET 字符串是不可变的? [复制]

    这个问题在这里已经有答案了 众所周知 String是不可变的 String不可变的原因是什么以及引入字符串生成器类是可变的 不可变类型的实例本质上是线程安全的 因为没有线程可以修改它 所以消除了线程以干扰另一个线程的方式修改它的风险 引用本