• .NET4.0中非常好用的一个东西Tuple


           最近发现了.NET4.0中一个非常好用的东西Tuple,自从知道了它之后,发现我的代码里面到处都是它的身影。那么Tuple究竟是何物呢?

           在知道Tuple之前,我经常碰到要使用一些记录的集合,如果每条记录只有一个元素,一般都是用List来存储,如果每条记录,我想记录两个属性,我一般用Dictionary<int,int>来存储,但是如果每个记录要记录三个属性,甚至四个属性的时候,那么我们只能定义一个数据结构或者实体类来进行存储,然后再把这个实体装到List中去。但是大多数时候,这么一个List的列表只是临时用一下,所以如果再去定义一个数据结构,就觉得有点不划算,那该怎么办呢?这时Tuple就该上场了。

          Tuple是元组的意思,它有八种形式(注意这里并不是说Tuple类有八种构造函数,而是八个不同的类,每种形式都是一个单独的类),它里面可以装任意多的元素,它的形式如下:

    image

          如果你的元素个数小于8,那么你可以直接调用相应的构造函数,如果你的元素个数大于8,那也不要紧,我们可以看到最后一个构造函数的最后一个参数是TRest,TRest也是Tuple类型的,这就说明,你可以在Tuple里面加入任意多的元素。

          下面以Tuple<T1>为例,来看看它里面具体的内容,它的内部代码如下:

    [Serializable]
    public class Tuple<T1> : IStructuralEquatable, IStructuralComparable, IComparable, ITuple
    {
        private readonly T1 m_Item1;
        public T1 Item1
        {
            get
            {
                return this.m_Item1;
            }
        }
        int ITuple.Size
        {
            get
            {
                return 1;
            }
        }
        public Tuple(T1 item1)
        {
            this.m_Item1 = item1;
        }
        public override bool Equals(object obj)
        {
            return ((IStructuralEquatable)this).Equals(obj, EqualityComparer<object>.Default);
        }
        bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer)
        {
            if (other == null)
            {
                return false;
            }
            Tuple<T1> tuple = other as Tuple<T1>;
            return tuple != null && comparer.Equals(this.m_Item1, tuple.m_Item1);
        }
        int IComparable.CompareTo(object obj)
        {
            return ((IStructuralComparable)this).CompareTo(obj, Comparer<object>.Default);
        }
        int IStructuralComparable.CompareTo(object other, IComparer comparer)
        {
            if (other == null)
            {
                return 1;
            }
            Tuple<T1> tuple = other as Tuple<T1>;
            if (tuple == null)
            {
                throw new ArgumentException(Environment.GetResourceString("ArgumentException_TupleIncorrectType", new object[]
                {
                    base.GetType().ToString()
                }), "other");
            }
            return comparer.Compare(this.m_Item1, tuple.m_Item1);
        }
        public override int GetHashCode()
        {
            return ((IStructuralEquatable)this).GetHashCode(EqualityComparer<object>.Default);
        }
        int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
        {
            return comparer.GetHashCode(this.m_Item1);
        }
        int ITuple.GetHashCode(IEqualityComparer comparer)
        {
            return ((IStructuralEquatable)this).GetHashCode(comparer);
        }
        public override string ToString()
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append("(");
            return ((ITuple)this).ToString(stringBuilder);
        }
        string ITuple.ToString(StringBuilder sb)
        {
            sb.Append(this.m_Item1);
            sb.Append(")");
            return sb.ToString();
        }

          从上面的代码中可以看出几点,一是它实现了四个接口,最主要是ITuple这个接口,只要实现了这个接口,那么它就是Tuple的一个实例。第二个,我们可以看出来,它里面的元素是只读的,也就是说不能对里面的元素进行赋值,如果想得到这个元素的值,那么就直接调用对象的Item属性,Item1代表第一个元素的值,Item2代表第二个元素的值,依此类推。

          除了上面的八种Tuple类,Tuple还有一个静态类,在这个静态类里面有一个Create方法,这个方法有8种重载,下面看一下静态的Tuple类:

    public static class Tuple
    {
        public static Tuple<T1> Create<T1>(T1 item1)
        {
            return new Tuple<T1>(item1);
        }
        public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
        {
            return new Tuple<T1, T2>(item1, item2);
        }
        public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3)
        {
            return new Tuple<T1, T2, T3>(item1, item2, item3);
        }
        public static Tuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 item1, T2 item2, T3 item3, T4 item4)
        {
            return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4);
        }
        public static Tuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
        {
            return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5);
        }
        public static Tuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6);
        }
        public static Tuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7);
        }
        public static Tuple<T1, T2, T3, T4, T5, T6, T7, Tuple<T8>> Create<T1, T2, T3, T4, T5, T6, T7, T8>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8)
        {
            return new Tuple<T1, T2, T3, T4, T5, T6, T7, Tuple<T8>>(item1, item2, item3, item4, item5, item6, item7, new Tuple<T8>(item8));
        }
        internal static int CombineHashCodes(int h1, int h2)
        {
            return (h1 << 5) + h1 ^ h2;
        }
        internal static int CombineHashCodes(int h1, int h2, int h3)
        {
            return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2), h3);
        }
        internal static int CombineHashCodes(int h1, int h2, int h3, int h4)
        {
            return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2), Tuple.CombineHashCodes(h3, h4));
        }
        internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5)
        {
            return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2, h3, h4), h5);
        }
        internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6)
        {
            return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2, h3, h4), Tuple.CombineHashCodes(h5, h6));
        }
        internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7)
        {
            return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2, h3, h4), Tuple.CombineHashCodes(h5, h6, h7));
        }
        internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7, int h8)
        {
            return Tuple.CombineHashCodes(Tuple.CombineHashCodes(h1, h2, h3, h4), Tuple.CombineHashCodes(h5, h6, h7, h8));
        }

       所以我们在使用的时候,可以有两种方式,一种是通过创建Tuple对象,另外一种就是通过静态类的Create方法。下面看一下具体的使用示例:

    //Tuple中的值都是只读的,只能通过构造函数赋值
     
    //创建一个元素的Tuple元组
    Tuple<int> tuple = new Tuple<int>(5);
    //Tuple<int> tuple = Tuple.Create(5);//等同于第一种方式
    int a = tuple.Item1;
     
    //创建三个不同类型的元组
    Tuple<int, string, float> t = new Tuple<int, string, float>(1,"Tom",99.85f);
    //Tuple<int, string, float> t = Tuple.Create(1, "Tom", 99.85f);//等同于第一种方式
    int grade = t.Item1;
    string name = t.Item2;
    float score = t.Item3;
     
    //还可以定义Tuple的集合
    List<Tuple<int, string, float>> tupleList = new List<Tuple<int, string, float>>();

        看了上面的用法,是不是觉得很方便,不过还有一点需要注意的是,如果想创建8个元素的Tuple,可以使用下面的方法:

    Tuple<int, int, int, int, int, int, int, Tuple<int>> tu1 = new Tuple<int, int, int, int, int, int, int, Tuple<int>>(1,2,3,4,5,6,7,new Tuple<int>(8));

         因为最后一个元素必须是ITuple类型的,所以在使用的时候一定要小心。如果用下面的这种方式就会报错:

    //使用的时候会报错,因为最后一个参数必须是Tuple实例类型的
    var tu2 = new Tuple<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7,8);

         可以看一下它的构造函数里面是怎样实现的:

    public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest)
    {
        if (!(rest is ITuple))
        {
            throw new ArgumentException(Environment.GetResourceString("ArgumentException_TupleLastArgumentNotATuple"));
        }
        this.m_Item1 = item1;
        this.m_Item2 = item2;
        this.m_Item3 = item3;
        this.m_Item4 = item4;
        this.m_Item5 = item5;
        this.m_Item6 = item6;
        this.m_Item7 = item7;
        this.m_Rest = rest;
    }

         它在构造函数里面经过了判断,如果不是ITuple类型就会抛出异常。不过可以使用静态Tuple类的Create方法来创建,代码如下:

    //使用静态Tuple类的Create方法,最后一个参数不需要是Tuple类型的
    var tu3 = Tuple.Create<int, int, int, int, int, int, int, int>(1,2,3,4,5,6,7,8);

         究其所以然,来看看Create方法里面有什么诡异之处:

    public static Tuple<T1, T2, T3, T4, T5, T6, T7, Tuple<T8>> Create<T1, T2, T3, T4, T5, T6, T7, T8>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8)
    {
        return new Tuple<T1, T2, T3, T4, T5, T6, T7, Tuple<T8>>(item1, item2, item3, item4, item5, item6, item7, new Tuple<T8>(item8));
    }

         可以看出,实际上第八个参数也需要是ITuple类型的,只不过是它在内部帮助我们转换了而已。

         Tuple介绍完了,是不是觉得很有用呢,赶快在你的程序中体验一下吧。

         主要参考了《你必须知道的.net》里面的内容,所以跟书里面的介绍很类似,但绝不是抄袭,自己按照他的思路一步步实验过。很佩服anytao,以后争取先自己分析,再来阅读书上的内容。

  • 相关阅读:
    python3给socket模块设置代理
    yield、greenlet与协程gevent
    线程池
    并发通信、生产者与消费者模型
    多进程和多线程
    非阻塞套接字与IO多路复用
    14.python模块之subprocess
    判断页面是否滑到底部
    @vue/cli 3.x 版本配置productionGzip提高性能
    vue跳转到指定位置
  • 原文地址:https://www.cnblogs.com/xiaoxiangfeizi/p/2790159.html
Copyright © 2020-2023  润新知