既前两篇之后,这一篇我们讨论通过struct 关键字自定义值类型。

在第一篇已经讨论过值类型的优势,节省空间,不会触发Gargage Collection等等。

在对性能要求比较高的场景下,通过struct代替类是不错的选择。

那么,比如我们定义一个Point 类型,里面包含两个左边X, Y。

    public struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
}

是不是这样就OK了呢?

当然不是。因为我们必须尽量避免这个值类型被装箱。

一个良好的值类型的定义,必须充分考虑到这个值类型的使用场景,然后定义好所需要的成员函数,从而避免有的函数调用不到而将值类型装箱的情况。比如说,如果这个Point可能会被放到某个容器中,并且排序,那么Point就必须实现接口System.IComparable,实现CompareTo 方法和接口System.IComprable<T>中类型安全的CompareTo 方法。

老赵前辈的博文防止装箱落实到底,只做一半也是失败 给了一个非常好的例子,我把它引用过来做一点讨论。

博文中的场景是struct所定义的值类型MyKey需要用作字典的键。

我们以System.Collections.Hashtable为例,其构造函数为

public Hashtable(
int capacity,
IEqualityComparer equalityComparer
)

这里面IEqualityComparer 是一个接口,用来作为HashTable的比较器。这个接口包含两个函数:Equals 和 GetHashCode 。

(在System.Collections.Generic.Dictionary,以及其他一些集合的视线中,要求两个对象为了相等,必须具有相同的哈希码——CLR via  C# 第三版。所以在很多情况下,Equals 和 GetHashCode都是定义值类型必须重写的两个方法。)

当我们使用struct 定义的值类型来作为HashTable的key时,因为我们自定义的值类型中没有提供Equals 和 GetHashCode的实现,因此值类型被装箱,来调用ValueType的这两个函数。

那么如何实现Equals 和 GetHashCode这两个方法呢?

对于GetHashCode方法,我们使用

public override int GetHashCode() {}

来重写其内容,自定义的计算方式最好能够做到返回的hash值能均匀分布。

对于equals 呢?如果我们仅仅用如下方法是不够的

public override bool Equals(object that) {}

因为它提供的是和object类型的比较,我们真正需要的是和同样类型MyKey的比较。

那么是否再加上这个就够了?

public bool Equals(MyKey that) {}

确实差不多了,但是我们的MyKey需要指明是实现了哪一个接口。程序在运行时,这个接口中的Equals 方法因为在MyKey中被实现,所以才会直接调用MyKey中的 Equals方法。

原文中实现了IEquatable<MyKey>接口。

如果我们打开的Int32的定义看一看

namespace System
{public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<int>, IEquatable<int>
{
........ public override int GetHashCode()
{
return this;
} public override bool Equals(object obj)
{
return obj is int && this == (int)obj;
} public bool Equals(int obj)
{
return this == obj;
}
....
}
}

里面的Equals部分和 MyKey的定义一样,也是有两个实现。同时Int32 实现了IEquatable<int>接口。

相关阅读

[C#] 类型学习笔记一:CLR中的类型,装箱和拆箱

[C#] 类型学习笔记二:详解对象之间的比较

[C#] 类型学习笔记三:自定义值类型的更多相关文章

  1. IOS 学习笔记 2015-03-20 OC-数值类型

    一 定义 在Objective-C中,我们可以使用c中的数字数据类型,int.float.long等.它们都是基本数据类型,而不是对象.也就是说,不能够向它们发送消息.然后,有些时候需要将这些值作为对 ...

  2. python3学习笔记三(数字类型,字符串)

    数字(Number)类型 有四种类型:整数.布尔型.浮点数和复数 int整数 bool布尔,如True float浮点数,1.23 complex复数,1+2j.1.2+2.3j 内置的 type() ...

  3. Java 学习笔记 (三) Java 日期类型

    以下内容摘自:  https://www.cnblogs.com/crazylqy/p/4172324.html import java.sql.Timestamp; import java.text ...

  4. Netty学习笔记(三) 自定义编码器

    编写一个网络应用程序需要实现某种编解码器,编解码器的作用就是讲原始字节数据与自定义的消息对象进行互转.网络中都是以字节码的数据形式来传输数据的,服务器编码数据后发送到客户端,客户端需要对数据进行解码, ...

  5. [C#] 类型学习笔记二:详解对象之间的比较

    继上一篇对象类型后,这里我们一起探讨相等的判定. 相等判断有关的4个方法 CLR中,和相等有关系的方法有这么4种: (1) 最常见的 == 运算符 (2) Object的静态方法ReferenceEq ...

  6. [C#] 类型学习笔记一:CLR中的类型,装箱和拆箱

    在学习.NET的时候,因为一些疑问,让我打算把.NET的类型篇做一个总结.总结以三篇博文的形式呈现. 这篇博文,作为三篇博文的第一篇,主要探讨了.NET Framework中的基本类型,以及这些类型一 ...

  7. javascript学习笔记(四) Number 数字类型

    数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数  toExponential() 方法 用科学 ...

  8. [读书笔记]C#学习笔记三: C#类型详解..

    前言 这次分享的主要内容有五个, 分别是值类型和引用类型, 装箱与拆箱,常量与变量,运算符重载,static字段和static构造函数. 后期的分享会针对于C#2.0 3.0 4.0 等新特性进行. ...

  9. Hadoop学习笔记—5.自定义类型处理手机上网日志

    转载自http://www.cnblogs.com/edisonchou/p/4288737.html Hadoop学习笔记—5.自定义类型处理手机上网日志 一.测试数据:手机上网日志 1.1 关于这 ...

随机推荐

  1. @Configuration和@Bean

    @Configuration可理解为用spring的时候xml里面的标签 @Bean可理解为用spring的时候xml里面的标签 Spring Boot不是spring的加强版,所以@Configur ...

  2. avalonJS入门

    前端神器avalonJS入门(一) posted @ 2014-10-31 17:44 vajoy 阅读(8759) 评论(42) 编辑 收藏   avalonJS是司徒正美开发和维护的前端mvvm框 ...

  3. canvas学习(三):文字渲染

    一.绘制基本的文字: var canvas = document.getElementById("myCanvas") var ctx = canvas.getContext('2 ...

  4. 我的Vscode配置

    "editor.fontSize": 17,//字体大小 "editor.wordWrap": "on",//软换行 "files ...

  5. Python运行的方式

    Python的运行方式多种多样,下面列举几种: 交互式 在命令行中输入python,然后在>>>提示符后面输入Python语句,这里需要注意: 1 语句前面不能有空格,否则会报错 2 ...

  6. 第十九次ScrumMeeting会议

    第十九次Scrum Meeting 时间:2017/12/9 地点:三公寓大厅 人员:蔡帜 王子铭 游心 解小锐 王辰昱 李金奇 杨森 陈鑫 赵晓宇 照片: 目前工作进展 名字 今日 明天的工作 蔡帜 ...

  7. sublime text 输入法不跟随光标

    1.引子 sublime text 有个BUG,那就是不支持中文的鼠标跟随(和PS类似输入的光标和文字候选框不在一起).如下图: 2.插件 安装IMESupport插件即可插件,这款插件是日本人写的. ...

  8. Firefox火狐浏览器 修改默认搜索引擎

    如图:

  9. 简述在akka中发送消息的过程

    在flink的数据传输过程中,有两类数据,一类数据是控制流数据,比如提交作业,比如连接jm,另一类数据是业务数据.flink对此采用了不同的传输机制,控制流数据的传输采用akka进行,业务类数据传输在 ...

  10. C#中的is和as操作符

    在C#语言中进行类型转换的操作符is和as.is和as都是强制类型转换,但这两者有什么相同之处和不同之处呢?在使用is和as需要注意哪些事项?下面我们从简单的代码示例去探讨这个简单的问题.注:此博文只 ...