不可变数据类型

news/2024/11/17 23:36:39/

不可变对象
不可变(immutable): 即对象一旦被创建初始化后,内存中该类型的值永远不会改变,之后的每次改变都会产生一个新对象。
作为不可变类型,最主要的特性表现是:一旦创建,只要修改,就会在托管堆上创建一个新的对象实例,而且和上一个对象实例是相邻的,在托管堆上分配到一块连续的内存空间。
例1:
string str=“zhjajihfgm”;
str.Substring(0, 6)
c#中的string是不可变的,Substring(0, 6)返回的是一个新字符串值,而原字符串在共享域中是不变的。另外一个StringBuilder是可变的,这也是推荐使用StringBuilder的原因。
例2:
class Contact
{
public string Name { get; set; }
public string Address { get; set; }
public Contact(string contactName, string contactAddress)
{
Name = contactName;
Address = contactAddress;
}
}
var mutable = new Contact(“二毛”, “清华”);
mutable.Name = “大毛”;
mutable.Address = “北大”;
我们实例化Contact赋值给mutable,随后我们可以修改Contact对象内部字段值,它已经不是初始后的值,可称为可变(mutable)对象。
可变对象在多线程并发中共享,是存在一些问题的。多线程下A线程赋值到 Name = “大毛” 这一步,其他的线程有可能读取到的数据就是:
mutable.Name == “大毛”;
mutable.Address == “清华”;
很明显这样数据完整性就不能保障,也有称数据撕裂。我们把可变对象更改为不可变对象如下:
public class Contact2
{
public string Name { get; private set; }
public string Address { get; private set; }
private Contact2(string contactName, string contactAddress)
{
Name = contactName;
Address = contactAddress;
}
public static Contact2 CreateContact(string name, string address)
{
return new Contact2(name, address);
}
}
使用时只能通过Contact2的构造函数来初始化Name和Address字段。Contact2此时即为不可变对象,因为对象本身是个不可变整体。通过使用不可变对象可以不用担心数据完整性,也能保证数据安全性,不会被其他线程修改。

不可变对象如下:
string
ImmutableStack
ImmutableQueue
ImmutableList
ImmutableHashSet
ImmutableSortedSet
ImmutableDictionary
ImmutableSortedDictionary
使用如下,
ImmutableStack a1 = ImmutableStack.Empty;
ImmutableStack a2 = a1.Push(10);
ImmutableStack a3 = a2.Push(20);
ImmutableStack a4 = a3.Push(30);
ImmutableStack iv3 = a4.Pop();
使用Net不可变列表集合有一点要注意的是,当我们Push值时要重新赋值给原变量才正确,因为push后会生成一个新对象,原a1只是旧值:
ImmutableStack a1 = ImmutableStack.Empty;
a1.Push(10); //不正确,a1仍是空值值,push会生成新的栈。
a1 = a1.Push(10); //需要将新栈重新赋值给a1
不可变对象优点
集合共享安全,从不被改变
访问集合时,不需要锁集合(线程安全)
修改集合不担心旧集合被改变
保证数据完整性,安全性
不可变对象缺点
当每次对象/集合操作都会返回新值。而旧值会保留一段时间,会使内存有极大开销,还会给GC造成回收负担,性能也比可变集合差(大约相差近40倍)。
跟string和StringBuild一样,Net提供的不可变集合也增加了批量操作的API,用来避免大量创建对象:
ImmutableList immutable = ImmutableList.Empty;
//转换成可批量操作的集合
var immutable2 = immutable.ToBuilder();
immutable2.Add(“xx”);
immutable2.Add(“xxx”);
//还原成不可变集合
immutable = immutable2.ToImmutable();

这里主要讲的是不可变集合主要应用场景例如,类似迅雷的下载任务、撤销操作用来记录操作的集合等。这类场景通常不会对其中某一个元素内容进行编辑而且操作元素的频率并不频繁,同时还满足多线程安全避免加锁操作影响程序性能。


http://www.ppmy.cn/news/40983.html

相关文章

cv2(OpenCV)下载安装

cv2对应库是OpenCV,官网下载链接:https://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv 最好下载对应python版本的,通过pip命令安装可能会出现版本过高或者过低的问题,导致import cv2没问题,但是内部函数无法调用。 …

CSS选择器基础1.1(查找标签)

1,标签选择器(以标签名命名的选择器) 结构: 标签名{CSS属性名:属性值;} 注:选中所有的这个标签都生效CSS。 2,类选择器 结构: .类名{CSS属性名:属性值;} 作用:通过类…

「MongoDB」时序数据库和MongoDB第二部分-模式设计最佳实践

在上一篇博客文章时间序列数据与MongoDB:第一部分-简介中,我们介绍了时间序列数据的概念,然后介绍了一些可以用于帮助收集时间序列应用程序需求的发现问题。对这些问题的回答有助于指导支持大容量生产应用程序部署所需的模式和MongoDB数据库配…

接口自动化【一】(抓取后台登录接口+postman请求通过+requests请求通过+json字典区别)

文章目录 前言一、requests库的使用二、json和字典的区别三、后端登录接口-请求数据生成四、接口自动化-对应电商项目中的功能五、来自postman的代码-后端登录总结前言 记录:json和字典的区别,json和字段的相互转化;postman发送请求与Python…

第三章 运算符

文章目录1. 什么是运算符2 算术运算符2.1 基本四则运算符 、-、*、/、%2.2 增量赋值运算符 、- 、* 、/ 、%2.3 自增/自减运算符 、--3. 关系运算符4. 逻辑运算符5. 位运算符6. 移位运算7. 条件运算符8. 运算符的优先级1. 什么是运算符 计算机的最基本的用途之一就是执行数学运…

一篇搞定Lambda和Stream流

一、Lambda表达式 jdk8中的语法糖,优化某些匿名内部类的写法,函数式编程的重要体现,不再关注对象是什么,更关注数据进行了什么操作 1、练习 练习1 练习2 练习3 练习4 练习5 2、省略规则 参数类型可以省略方法体只有一句代码时…

分库分表的知识

简述 分库分表是数据量大的场景下的一种技术优化方案,当数据量逐渐增大,单库单表已经无法满足业务需求时,分库分表成为了一个必要的选项。 分库分表可以有效地缓解数据库的性能瓶颈,提高系统的稳定性和可扩展性。但是&#xff0c…

C语言学习路径指南:从入门到精通

本期是关于C语言学习路径的介绍,是根据我发布的博客来进行汇总,也是对C语言知识的一个整体的串联总结,仅代表我的个人观点! C语言专栏:C语言:从入门到精通 目录 1.初始C语言 2.初阶C语言 3.进阶C语言 1…