zoukankan      html  css  js  c++  java
  • [C#] 类型学习笔记三:自定义值类型

    既前两篇之后,这一篇我们讨论通过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#] 类型学习笔记二:详解对象之间的比较

  • 相关阅读:
    AcWing 204. 表达整数的奇怪方式 / Strange Way To Express Integers
    Codeforces Edu Round 67 A-C + E
    Codeforces Edu Round 66 A-E
    Codeforces Edu Round 65 A-E
    Codeforces Edu Round 64 A-D
    Codeforces Edu Round 63 A-E
    Codeforces Edu Round 62 A-E
    Codeforces Edu Round 61 A-C + F
    python 线程池和锁
    python 线程
  • 原文地址:https://www.cnblogs.com/felixfang/p/3633422.html
Copyright © 2011-2022 走看看