《Effective C#》Item 7:推荐使用不可改变的原子值类型

day17-面向对象作业 定义一个矩形类,拥有属性:长、宽 拥有方法:求周长、求面积 class Rectangle: def __init__(self, length, width): self.length = length self.width = width def perimeter(self): result = (self.width+self.length)*2 print("该矩形的周长为:%s" % result) .. 阅读详情

首先来解释一下标题,原标题为《Prefer Immutable Atomic Value Type》,因此对于标题的理解要分成三部分,第一部分为不可改变,第二部分为原子,最后一个部分为值类型。最后一部分,我不多说了,限制此章适用的范围。对于什么是不可改变类型,这里的意思是指此类型的变量一旦产生其成员就不能发生变化。至于原子类型,我以前在优快云也经常提到,例如保证操作的原子性之类的语句,那么一个原子类型,其的子成员为不可分割的一部分,不能单独被操作。

 

听了标题解释,难免有些人会问,为什么要加上这样的限制,或者说这样做的好处是什么。为了解开这个疑团,我用一个例子来说明,去定义一个电话号码的值类型,一般形式如下:

    public struct Phone

    {

        private string strCountry_Code;

        private string strCity_Code;

        private string strPhone_Number;

        public string Country_Code

        {

            get{ return strCountry_Code; }

            set{ strCountry_Code = value;}

        }

        public string City_Code

        {

            get{ return strCity_Code; }

            set{ strCity_Code = value;}

        }

        public string Phone_Number

        {

            get{ return strPhone_Number; }

            set{ strPhone_Number = value;}

        }

 

        // Constructor

        public Phone( string sCountry_Code, string sCity_Code, string sPhone_Number )

        {

            strCountry_Code = sCountry_Code;

            strCity_Code = sCity_Code;

            strPhone_Number = sPhone_Number;

        }

    }

 

这样去初始化一个Phone类型变量的话,同时也可以做类似如下的相关操作。

    Phone myPhone = new Phone( "086", "010", "66666666" );

    myPhone.City_Code = "021";

    myPhone.Phone_Number = "777777777";

 

大多数人觉得如上的代码没有什么问题,不过稍微明眼的人看了如上的代码,就会立刻觉得有潜在的危险。作为一个Phone类型变量来说,国家区号,城市区号,以及电话号码来说是一个整体。因此动态修改其中的某一个值,会造成其他两个无效。也就是说如上的代码直接修改City_Code的时候,对于myPhone来说其他两个变量Country_Code以及Phone_Number来说,此时是无效的。不过这种错误在单线程中不是很明显,但是在多线程中是致命的,而且很难查出来。有人可能会说了,在修改的时候加上Lock语句或者互斥标识来避免。这样是可以避免,但是试问一下,类型是你创建的,你怎么要求别人在使用你这个类型的时候做过多的操纵呢,为什么你不在创建此类型的时候就直接把这条路堵死。如果明白了这一点,就理解了这篇文章推荐的目的,即与其后期增加代码弥补,不如在前期就编写正确的代码。

 

知道这样做的原因,接下来就是如何去实现。不过在实现之前,要区分什么样的数据类型可以定义成不可变的原子类型。也就是说,你如何区分一个类型是一个整体,而且每个分支不能独立于整体而存在。例如对于联系方式这个类型来说,它包括电话号码、住址等等。它可以看为一个整体,但是分支可以脱离这个整体而存在,因此它不是一个原子类型。对于如何具体区分,很难有一个统一的方法,毕竟适应的环境不同,操作以及实现也不同。不过对于原子类型,有一个唯一判断方式,就是每个分支能否独立于整体而被操作,这个的是与否决定是否为原子类型。

 

那么如何去定义一个不可变的原子值类型呢,大致要对原有的类型做两个处理,一个就是把所有成员加上readonly标示,即只能在构造函数中被修改;另一个就是删除属性set部分。对于Phone这个类型来说,经过处理后,正确的形式如下:

    public struct Phone

    {

        private readonly string strCountry_Code;

        private readonly string strCity_Code;

        private readonly string strPhone_Number;

        public string Country_Code

        {

            get{ return strCountry_Code; }

        }

        public string City_Code

        {

            get{ return strCity_Code; }

        }

        public string Phone_Number

        {

            get{ return strPhone_Number; }

        }

 

        // Constructor

        public Phone( string sCountry_Code, string sCity_Code, string sPhone_Number )

        {

            strCountry_Code = sCountry_Code;

            strCity_Code = sCity_Code;

            strPhone_Number = sPhone_Number;

        }

    }

 

这样对于一个Phone类型变量,只能通过new来创建(也就是说在输入三个有效的数据后,一个Phone类型变量才能产生)。

 

在此有人会问,除了new是否还有其他方法来进行修改。这是没有任何问题的,首先你只要理解了原子类型的意义,保证分支不会单独被修改即可,因此可以实现类似于“Phone.Parse”或者“Phone.From”之类的函数来形成一个新的Phone变量。

 

在实现不可变的原子值类型的时候,要防止类型中包括引用类型分支的时候,在进行成员赋值的时候,防止浅copy,这方面我就不多说了,参看我以前写的文章就可以明白(这里的目的也就是一点,防止局部破坏原子类型的分支)。

http://blog.youkuaiyun.com/Knight94/archive/2006/07/01/861383.aspx

http://blog.youkuaiyun.com/Knight94/archive/2006/06/04/772886.aspx

 
魔兽世界怀旧服宏命令全解析:从自动换装到智能判定,老玩家才知道的黑科技 本文全面解析魔兽世界怀旧服宏命令的高级应用,从自动换装到智能判定,揭秘老玩家专属的黑科技技巧。深入探讨怀旧服特有的宏命令机制,包括施法队列、装备切换系统和职业专属技巧,帮助玩家在经典旧世版本中提升战斗效率。 阅读详情

相关推荐

OpencvSharp学习笔记(一):图片的打开,保存灰度化,保存

近来萌生了学习OpenCv的想法,经过度娘得知老夫会的C#不能直接用OpenCv,只能用他的儿子OpenCvSharp与EmguCV,奈何奈何,这两玩意的资料少的出奇,只能慢慢的摸索了,EmguCV先不说,老夫找到了牛批的资料,先摸索OpencvSharp吧 首先打开VS通过Nuget安装 选择版本后点击安装就OK了. 安装完成后,引用里面就有以下的玩意儿了… 废话不多说了,在写程序前先 using OpenCvSharp 图片打开,灰度化,保存代码如下: static void Main(strin

猥琐de专注 7186

Python的数据类型

目录数据类型与数据结构数据类型数据结构举例基础结构运行特点 数据类型与数据结构 定义 数据类型 = 数据 + 处理方式 数据类型是一个元素的集合和定义在这个元素集合上的一组操作的总称 数据结构 = 数据 + 组成方式 数据结构是相互之间存在一种或多种特定关系的数据元素的集合 结论 数据类型包含数据结构 数据类型 Python 中有六个标准数据类型 1. 数字 Number 2. 字符串 String 3. 列表 List 4. 元组 Tuple 5. 字典 Dict

昊大侠的博客 8414

【unity】Google 登录和Google支付接入unity

google 支付 google 登录

云渊寒烬 8495

不可变和可hash的关系

不可变 值类型都是不可变的:string 、int、元组 可hash 1、在对象的生命周期内,他的散列值是不变的,如果这种对象相等,他们hash值一定是一样的,可hash 2、原子不可变(注:例如元组 成员中都是不可变数据类型)的数据类型可hash 结论: 1、不可变的不一定可hash ,例如 元组 (‘a’,[1,2]) 虽然元组是不可变的数据类型,但是不满足原子不可变性 2、原子都是不可变的不...

caca95的博客 1274

A-Level CS 计算机科学 考试知识点——考试介绍&第1章

前言:该系列文章是本人在给学生辅导本课程的过程中结合英文教材所总结的,该系列共分为30章,主要介绍了考试的核心知识点。若需要A-Level CS 计算机科学考试辅导也可以私信我。 目录 关于A-Level CS 计算机科学考试 考试简介 考试内容 考试时间 评分情况 第1章 信息表示 本章学习内容 1.01 数字系统 1.02 数字的内部编码 整数编码(Coding for integers) 二进制编码的十进制(Binary coded decimal——BCD) 1.03.

王俊的博客 6454

山东大学FPGA课程实验一 加法器设计

电子设计自动化与FPGA设计,实验一 加法器设计

2503_91283667的博客 869

[C#]关于变量读写的原子性

假如读写变量的类型大小不超过一个本机(指针大小)整数,CLR就能保证该类型不会被部分性地读取或写入。所以,64位操作系统保证能够原子性的读写一个long(64位)。然而128位变量(decimal)的读写就不保证是原子性的。因此,通过写操作更改一个decimal变量时,可能会在仅仅复制了32位之后被打断,造成以后读取一个不正确的值,这称为一次被撕裂的读取。 即在64位操作系统下,对64位以下包括64位大小的变量进行读写操作时,是原子性的,32位同理。 ...

牛哞哞的博客 1664

LPDDR4x 深度解析(3) - SDRAM核心操作机制

本文深入解析LPDDR4x SDRAM的核心操作机制,包括基础架构、刷新操作、读写流程及低功耗设计。详细介绍了存储阵列、地址解码器等关键模块,以及自刷新与自动刷新模式的区别。通过实测数据和技术细节,揭示LPDDR4x在性能优化和功耗控制方面的创新设计,为硬件工程师提供实用参考。

weixin_29278805的博客 307

c#引用类型变量在程序中的变化

这是我的第一篇博客。 想到写博客,是因为记录在纸上的东西,总怕哪天一丢,那些出过的错误又回来缠绕自己。 好了,那就步入正题吧! c#应用类型,具体请看别人写的博客吧 这里有一个有趣的现象: class Program     {         static void Main(string[] args)         {             object a =

u010653281的博客 720

Ubuntu使用gstreamer开发USB相机应用(一)

Ubuntu使用gstreamer开发USB相机应用(一) 包括:gstreamer安装,测试。使用v4l2测试USB相机。使用gstreamer采集相机

Alon1787的博客 2735

图像分割 - 使用Mask R-CNN模型在COCO数据集上进行图像分割任务

图像分割是计算机视觉领域的一个重要任务,它旨在将图像中的每个像素分类为对象或背景。Mask R-CNN是一种基于区域的卷积神经网络,可用于图像分割任务。它是Faster R-CNN的扩展,将目标检测与图像分割结合起来,能够同时检测和分割对象。在本博客中,我们将使用Mask R-CNN模型在COCO数据集上进行图像分割任务。我们将介绍如何下载和准备COCO数据集,以及如何使用Mask R-CNN模型进行训练和推理。

斌擎科技 1188

[转载]《Effective C#》Item 7:推荐使用不可改变的原子值类型

《Effective C#》Item 7:推荐使用不可改变的原子值类型《Effective C#》Item 7:推荐使用不可改变的原子值类型 首先来解释一下标题,原标题为《Prefer Immutable Atomi...

congji3817的博客 99

1 硬件工程师笔面试高频知识考点真题及解析——电阻

本文系统介绍了电阻的基础知识、选型要点及各类特殊电阻的应用。主要内容包括:1. 电阻选型需考虑阻值、封装、功率、精度、耐压等参数;2. 高频信号优先选用小封装电阻以减小寄生参数;3. 采样电阻需高精度、低温漂以保证测量准确性;4. 详细解析了上拉/下拉电阻、0欧电阻、磁珠等元件的特性与区别;5. 介绍了压敏电阻、热敏电阻等特殊电阻的工作原理及应用场景;6. 阐述了阻抗匹配的重要性及常见匹配方法。文章为电子工程师提供了全面的电阻选型与应用指南。

XU157303764的博客 2835

转:《Effective C#》Item 7:推荐使用不可改变的原子值类型

转:http://dev.youkuaiyun.com/author/Knight94/5582b364fc744be09bca2dca36786322.html《Effective C#》Item 7:推荐使用不可改变的原子值类型 首先来解释一下标题,原标题为《Prefer Immutable Atomic Value Type》,因此对于标题的理解要分成三部分,第一部分为不可改变,

flyskylf的专栏 659

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

《Effective C#》Item 2:定义常量的两种方法

在C#中定义常量的方式有两种,一种叫做静态常量(Compile-time constant),另一种叫做动态常量(Runtime constant)。前者用“const”来定义,后者用“readonly”来定义。 对于静态常量(Compile-time constant),它的书写方式如下:public const int MAX_VALUE = 10;为什么称它为静态常量呢,因为

愚翁专栏 6099

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

《Effective C#》Item 11:提倡使用foreach语句来进行循环操作

循环语句是编程的基本语句,在C#中除了沿用C语言的循环语句外,还提供了foreach语句来实现循环。那么我要说的就是,在循环操作中尽量使用foreach语句来实现。 为了来更好地说明为什么要提倡使用foreach,用如下三种不同方式来编写循环语句。        int[] nArray = new int[100];         // Use "foreach" to l

愚翁专栏 6313

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

《Effective C#》Item 19:推荐在继承中使用接口

.Net提供了接口,这个不同于Class或者Struct的类型定义。接口有些情况,看似和抽象类一样,因此有些人认为在.Net可以完全用接口来替换抽象类。其实不然,接口和抽象类各有长处和缺陷,因此往往在应用当中,两者要结合来使用,从而互补长短。 接下来先说说抽象类和接口的区别。区别一,两者表达的概念不一样。抽象类是一类事物的高度聚合,那么对于继承抽象类的子类来说,对于抽象类来说,属于“是

愚翁专栏 8463

《Effective C#》Item 12:推荐使用成员初始化语句

为了方便内容的开展,先说说一个对象的构造过程。对于类型第一个实例的构造过程大致如下:1. 分配静态成员的内存空间,此时空间存储数据为0;2. 执行静态成员的初始化语句;3. 执行基类的静态构造函数;4. 执行类型的静态构造函数;5. 分配成员的内存空间,此时空间存储数据为0;6. 执行成员的初始化语句;7. 执行相应的基类构造函数;8. 执行类型的构造函数。

愚翁专栏 9596

[转载]《Effective C#》Item 2:定义常量的两种方法

《Effective C#》Item 2:定义常量的两种方法《Effective C#》Item 2:定义常量的两种方法 在C#中定义常量的方式有两种,一种叫做静态常量(Compile-time constant),...

congji3817的博客 115

Effective C#之Item 48:Learn About Tools and Resources

 v/:* {behavior:url(#default#VML);}o/:* {behavior:url(#default#VML);}w/:* {behavior:url(#default#VML);}.shape {behavior:url(#default#VML);} Normal 0 7.8 磅 0

一路采撷 1303

Effective C# Item 10: Understand the Pitfalls of GetHashCode()

Effective C# Item 10 : Understand the Pitfalls of GetHashCode() 这是本书中唯一一项不推荐大家使用的函数。如果不是为哈希序列(例如HashTable和Dictionary)设定键(key)的话,我们应当尽量避免使用GetHashCode()。这是因为当基类调用GetHashCode时会产生一系列的问题。对于引用类...

aijinyao5713的博客 133

C#学习资料《Effective C#》

Item 1: Always Use Properties Instead of Accessible Data Members《Effective C#》Item 1:用属性来访问类的私有成员http://blog.youkuaiyun.com/knight94/archive/2006/06/04/772886.aspxItem 2: Prefer readonly to const《Effectiv

SharpRose的专栏 1232
上一篇: 如何使用Base64进行加密和解密(续)
下一篇: 多线程断点续传研究之一
Knight94
博客等级 码龄25年 1013粉丝 87原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值