对像集合使用过程中的一些总结

1. 设计可比较大小的对像   

2. 针对数组元素的查询与转换   

3. 针对对像集合的标准查询   

1.设计可比较大小的对像

众所周知,数值型变量之间可以直接比较大小

 如:

 Int i=100;

 Int j=100;

 Console.Writeline(i>j); //输出false

 之所以可以比较两个整型变量的大小,是因为在数学上两个整数之间谁大谁小有明确定义,比较两个整形变量时,实际上比较的是这两个整形变量所保存数值的大小。

 然而同将同样的方法应用于引用类型的变量 ,问题来了,代码无法通过编译

 Object o1=new object();

 Object o2=new object();

 Console.WriteLine(o1 > o2);

 上述代码之所以不能通过编译,是因为两个变量引用了两个object类形的对像,而默认情况下两个object类型对像谁大谁小是未定义的。

但在某此具体的场景下,确定两个对像的大小是有意义的

比如判断两个圆的大小,半径相等的圆就可以认为是相等的圆,半径越大的圆也就越大,

如果用Circle类来表示一个圆,上述问题就转换为Circle对像的大小比较问题。

默认情况下,.Net Formework显示什么

Circle obj1 = new Circle() { Radio = 100 };

Circle obj2 = new Circle() { Radio = 100 };

Console.WriteLine(obj1 == obj2); //false

Console.WriteLine(obj1.Equals(obj2)); //false

虽然两个圆的半径是相等的,希望两个对像比较的结果是true,但由于对像变量obj1与obj2引用的是两个不同的对像,所以==返回false,equals也是比较两个对像是否引用同一对像,所以也返回false。

修改代码,实现IComparable接口,自定义一个CompareTo方法,用于比较大小

    class Circle:IComparable

    {

        public double Radio = 0; //半径

        public CircleCenter center; //圆心

        public int CompareTo(object obj)

        {

            double ret = Math.Abs((obj as Circle).Radio - this.Radio);

            if (ret==0)

                return 0;//相等

            if ((obj as Circle).Radio < this.Radio)

            {

                return 1;//大

            }

            return -1; //小

        }

    }

有许多情况,可能只需要知道两个对像是否相等,而不需要知道这两个对像谁大谁小,这时可以重写object类的equals方法

    public override bool Equals(object obj)

        {

            if (this.CompareTo(obj) == 0)

            {

                return true;

            }

            return false;

        }

重写或重载object.equals需满足三点

1.自反性:即自身与自身相等。a.Equals(a) 返回true

2.对称性:若a与b相等,则b与a也相等,这就是说a.Equals(b)与b.Equals(a)的值一次是相等的

3.传递性:若a与b相等,b与c相等,则a与c相等。这就是说如果a.Equals(b)和b.Equals(c)都为true,则a.Equals(c)的值也为true

重写了equals方法,马上就可以重载==运算符,若一个对像重载了==运算符,也必须重载!=运算符,这是一个编程的基本原则,

完整代码见下方 

 class Program
    {
        static void Main(string[] args)
        {
            Circle obj1 = new Circle() { Radio = 100 };
            Circle obj2 = new Circle() { Radio = 100 };
            Console.WriteLine(obj1.Equals(obj2)); //true
            Console.WriteLine(obj1.CompareTo(obj2));//0
            Console.WriteLine(obj1 != obj2); //false

            Circle[] circles = new Circle[4]{new Circle{Radio=10},
                                              new Circle{Radio=20},
                                              new Circle{Radio=15},
                                              new Circle{Radio=18}};
            Array.Sort(circles);
            foreach (Circle c in circles)
            {
                Console.WriteLine(c.Radio);
            }
                Console.ReadKey();
        }

    }
    class Circle:IComparable
    {
        public double Radio = 0; //半径
       // public CircleCenter center; //圆心
        public int CompareTo(object obj)
        {
            double ret = Math.Abs((obj as Circle).Radio - this.Radio);
            if (ret==0)
                return 0;//相等
            if ((obj as Circle).Radio < this.Radio)
            {
                return 1;//大
            }
            return -1; //小
        }
        //重写Equals方法
        public override bool Equals(object obj)
        {
            if (this.CompareTo(obj) == 0)
            {
                return true;
            }
            return false;
        }
        //覆盖Object类的GetHashCode方法
        public override int GetHashCode()
        {
            //整数部分与小数点后3位相同的对象生成相同的哈希值
            return (int)(Radio * 1000);
        }
        //重载相关运算符
        public static bool operator ==(Circle obj1, Circle obj2)
        {
            return obj1.Equals(obj2);
        }
        public static bool operator !=(Circle obj1, Circle obj2)
        {
            return !obj1.Equals(obj2);
        }
        public static bool operator >(Circle obj1, Circle obj2)
        {
            return obj1.CompareTo(obj2)==1;
        }
        public static bool operator <(Circle obj1, Circle obj2)
        {
            return obj1.CompareTo(obj2) == -1;
        }
    }

2.针对数组元素的查询与转换

在某些情况下可能会需要将数组中的元素转换为另一个类型,这个工作可以通过调用数组基类Array的ConvertAll方法实现:

    class Program
    {
        static void Main(string[] args)
        {
            int[] intArr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            double[] doublearr = Array.ConvertAll<int, double>(intArr, IntToDouble);
            foreach (double d in doublearr)
            {
                Console.WriteLine(d);
            }
            Console.ReadKey();
        }
        static Converter<int, double> IntToDouble = delegate(int value)
        {
            return (double)value;
        };

    }

当需要循环迭代数组中的所有元素,并且对这些元素都进行同样的处理工作时,可以调用数组基类的Array的Foreach<T>方法达到目的

    class Program
    {
        static void Main(string[] args)
        {
            //源数组
            int[] SourceArr = new int[] { 0, 1, 2, 3, 4, 5, 6 };
            //目标数组
            int[] TargetArr = new int[SourceArr.Length];
            int index=0;
            Action<int> DoubleArr = delegate(int element)
            {
                TargetArr[index++] = element * 2;
            };
            //循环源数组,把数据存入目标数组
            Array.ForEach<int>(SourceArr, DoubleArr);
            Array.ForEach<int>(TargetArr,element => { Console.WriteLine(element); });
            Console.ReadKey();
        }
    }

实际开发中数据排序很常见,数组基类Array直接就内置了相应的排序功能,比如选择择排序,冒泡排序

Sort方法是最简单的:例

 class Program
    {
        static void Main(string[] args)
        {
            int[] IntArr = new int[10];
            Random ran = new Random();
            for (int i = 0; i < IntArr.Length; i++)
            {
                IntArr[i] = ran.Next(1, 100);
            }
            Array.Sort(IntArr);
            Console.ReadKey();
        }
    }

当调用此方法时,要求数组中的元素要实现System.IComparable接口,否则此方法会抛出InvalidOperationException异常,如果数组中元素没有实现Icomparable接口 ,可以提供一个对像比较器完成排序,或者更简单些,不需要定义一个对像比较器,直接给Sort提供一个可以比较两对像大小的方法

    class Program
    {
        static void Main(string[] args)
        {
             Random ran = new Random();
             MyClass[] obj = new MyClass[10];
            for (int i = 0; i < obj.Length; i++)
            {
                obj[i] = new MyClass { value = ran.Next(1, 100) };
            }

           //定义一个委托,用于比较两个对像大小,当x>y时,返回一个正数,当x=y时,返回0,当x<y时返回负数
            Comparison<MyClass> WhoIsGreater = delegate(MyClass x, MyClass y)
            {
                if (x.value > y.value)
                    return 1;
                else if (x.value == y.value)
                    return 0;
                else
                    return -1;
            };

            //未排序前输出
            Array.ForEach(obj, element => { Console.Write(element.value + ","); });
            //排序

            Array.Sort(obj,WhoIsGreater);
            Console.WriteLine("");

           //排序后输出
            Array.ForEach(obj, element => { Console.Write(element.value + ","); });
            Console.ReadKey();
        }
    }

Sort方法提供了多个形式的重载,有一个重载可以实现两个数组的联动,假设有两个一样长度的数组(分别叫keys和Itmes),这两个数组的元素是一一对应的,这就是说,keys数组的第一个元素对应Items数据中的第一个元素,对Keys数组中的元素进行排序同时也会更改Items中的元素位置,以维护这两个数据元素间的连动关系。示例中字符串数组存放代表一周的七个英文单词,而int数组则保存1-7个整数,并且与字符串数组的星期单词是连动的

    class Program
    {
        static void Main(string[] args)
        {
            int[] Keys = new int[] { 7, 2, 3, 4, 1, 5, 6 };
            string[] Items = new string[] { "Sunday", "Wednesssday", "Thursday", "Tuesday", "Monday", "Friday", "Saturday" };  

            //对keys排序,对应的items也会跟着变

            Array.Sort<int,string>(Keys,Items);
            Array.ForEach(Keys, element => { Console.Write(element + ","); });
            Console.WriteLine("");
            Array.ForEach(Items, element => { Console.Write(element + ","); });
            Console.ReadKey();
        }
    }

有时可能希望保存在数组中的元素都满足特定的要求,数组基类Array提供了相应的静态方法完成这一工作

TrueForAll<T>方法所有的条件是否都满足,只要有一个不满足就返回false,代码示例如下:

    class Program
    {
        static void Main(string[] args)
        {
            Predicate<int> match = delegate(int value)
            {
                return value % 2 == 0;
            };
            int[] IntArr=new int[]{0,1,2,3,4,5,6,7,8,9};

            //判断数组元素是否都为偶数,true全部是偶数,如果有一个不是偶数即返回false
            bool IsAllEven = Array.TrueForAll(IntArr, match);

      }
    }

判断数组中是否存在满足某个特定元素可以用Exists<T>,代码示例如下:

    class Program
    {
        static void Main(string[] args)
        {
            int[] IntArr=new int[]{0,1,2,3,4,5,6,7,8,9};
            Predicate<int> ExistEventNumber = delegate(int value)
            {
                if (value > 8)
                    return true;
                return false;
            };
            bool IsExists = Array.Exists(IntArr, ExistEventNumber);
        }
    }

TrueForAll<T>跟Exists<T>区别在于:前者全部满足指定条件才返回true,后者只要有一个满足即返回true

数组基类Array还提供了一堆的方法用于查找元素

Find<T>:从数组开头查找匹配元素,FindLast<T>从数组结尾开始向前查找匹配元素

FindAll<T>:查找数据中满足特定条件的所有元素

FindIndex<T>:查找数组中满足特定条件的元素所在的位置(索引)

3. 对像集合的标准查询

.Net基类库中大多数集合都实现了IEnumerable<T>接口,从.Net3.5开始,.Net基类库中提供了一组针对IEnumerable<T>接口的扩展方法,为各种对像集合提供各种标准查询服务,这些扩展方法返回一个对像集合,可以使用foreach语句逐个访问这些对像,或者将其用作数据绑定控件的数据源,这组扩展方法功能强大,使用灵活,实际构成了LINQ技术大厦的地基

筛选:是指从对像集合中选出那些满足特定条件的对像,可通过where扩展方法实现,下图程序是从指定路径中获取包含指定字符的文件名

完整代码如下:

class FileBroseHelper

    {

        /// <summary>

        /// 取指定文件夹中的文件

        /// </summary>

        /// <param name="foldername"></param>

        /// <returns></returns>

        public static List<FileInfo> GetAllFileInFolder(string foldername)

        {

            try

            {

                List<FileInfo> files = null;

                if (!Directory.Exists(foldername))

                {

                    return null;

                }

                DirectoryInfo d = new DirectoryInfo(foldername);

                files = d.GetFiles().ToList();

                return files;

            }

            catch (Exception ex)

            {

                throw (ex);

            }

        }

        /// <summary>
        /// 将文件显示到listbox中
        /// </summary>
        /// <param name="file"></param>
        /// <param name="list"></param>

        public static void ShowFileListInListBox(IEnumerable<FileInfo> file, System.Windows.Forms.ListBox list)

        {

            list.Items.Clear();

            foreach (FileInfo f in file)

            {

                list.Items.Add(f);

            }

        }

    }

按钮事件如下:

  private void btnClick_Click(object sender, EventArgs e)
        {
            if (txtFolderNam.Text.Trim().Length == 0)
            {
                return;
            }
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                //获取选择的路径
                string foldername = folderBrowserDialog1.SelectedPath;
                labTitle.Text = foldername;
                //取该路径下所有文件
                List<FileInfo> files = FileBroseHelper.GetAllFileInFolder(foldername);
                IEnumerable<FileInfo> ret = files.Where<FileInfo>(file =>file.Name.IndexOf(txtFolderNam.Text)!=-1);
                //把筛选出来的文件名显示在listbox中
                FileBroseHelper.ShowFileListInListBox(ret, listBox1);
            }
        }

上述代码中Lambda表达式给Where扩展方法赋值,用到是的FilInfo是System.IO命名空间中的类,封装了文件的基本信息和常用操作。

投影:指把某对像集合中对像的部分属性抽取出来

数据转换:指将某对像集合中感兴趣的对像(或抽取它的部分字段/属性)转换为另一种类型的对像

代码见下方:

    class Program
    {
        static void Main(string[] args)
        {
            //转换为不同类型的集合
            IEnumerable<string> filelist = Directory.GetFiles("c:\\", "*.*");
            IEnumerable<FileInfo> files = filelist.Select(file => new FileInfo(file));
            foreach (FileInfo f in files)
            {
                Console.WriteLine(f);
            }
            //返回一个匿名对像的集合
          var items =filelist.Select(file=>{
                                            FileInfo f=new FileInfo(file);
                                            return new { FileName = f.Name, Size = f.Length };
                                           });
          foreach (var i in items)
          {
              Console.WriteLine(i.FileName + "," + i.Size);
          }
            Console.ReadKey();
        }
    }

排序:使用扩展方法OrderBy(升序),OrderByDescending(降序)进行排序

代码见下方:

    class Program
    {
        static void Main(string[] args)
        {
            Pet[] pets = new Pet[]{new Pet{Name="Tiger",Age=22},
            new Pet{Name="Lion",Age=17},
            new Pet{Name="rabbit",Age=18}};
            IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);
            foreach (var q in query)
            {
                Console.WriteLine(q.Age);
            }
            Console.ReadKey();

        }
    }
    class Pet
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

数据连接:指根据某个对像的属性将两个数据集合的对像连接起来,得到一个新的集合

    class Program
    {
        static void Main(string[] args)
        {
            A[] a = new A[10];
            B[] b = new B[10];
            for (int i = 0; i <10; i++)
            {
                a[i] = new A { AID = i, AName = "AName" + i.ToString() };
                b[i] = new B { BID = i, BName = "BName" + i.ToString() };
            }
            var result = a.Join(b, aobj => aobj.AID, bobj => bobj.BID, (aobj, bobj) => new { aobj.AID, aobj.AName, bobj.BName });
            foreach (var elem in result)
            {
                Console.WriteLine("{0},{1},{2}", elem.AID, elem.AName, elem.BName);
            }
            Console.ReadKey();
        }
    }
    class A
    {
        public int AID;
        public string AName;
    }
    class B
    {
        public int BID;
        public string BName;
    }

集合运算:常用的集合运算包括求交集,并集,差集等,.Net基类库提供了一组扩展方法来完成标准集合运算,例如union,contact,sum,intersect等

示例代码如下:

 class Program
    {
        static void Main(string[] args)
        {
            //创建一个多态对象集合
            IEnumerable<object> stuff = new object[] { new object(), 1, 3, 5, 7, 9, "\"thing\"", Guid.NewGuid() };
            //输出数组的内容
            Print("Stuff集合的内容: {0}", stuff);

            //偶数集合
            IEnumerable<int> even = new int[] { 0, 2, 4, 6, 8 };
            Print("偶数集合的内容: {0}", even);

            //从多态集合stuff中筛选中整数元素(全部为奇数)组成一个新集合
            IEnumerable<int> odd = stuff.OfType<int>();

            Print("奇数集合的内容: {0}", odd);

            //求两个集合的并集
            IEnumerable<int> numbers = even.Union(odd);
            Print("奇数与偶数集合的并集,成为一个整数集合: {0}", numbers);

            Print("整数集合与偶数集合的并集: {0}", numbers.Union(even));

            Print("整数集合与奇数集合相连接: {0}", numbers.Concat(odd));

            Print("整数集合与偶数集合的交集: {0}", numbers.Intersect(even));

            Print("整数集合与奇数集合连接,再删除重复值: {0}", numbers.Concat(odd).Distinct());


            if (!numbers.SequenceEqual(numbers.Concat(odd).Distinct()))
            {
                throw new Exception("Unexpectedly unequal");
            }
            else
            {

                Print("反转整数集合: {0}", numbers.Reverse());

                Print("求整数集合的平均值: {0}", numbers.Average());
                Print("求整数集合的总和: {0}", numbers.Sum());
                Print("求整数集合的最大值: {0}", numbers.Max());
                Print("求整数集合的最小值: {0}", numbers.Min());
            }

            Console.ReadKey();
        }

        private static void Print<T>(string format, IEnumerable<T> items)
        {
            StringBuilder text = new StringBuilder();

            foreach (T item in items.Take(items.Count() - 1))
            {
                text.Append(item + ", ");
            }


            text.Append(items.Last());
            Console.WriteLine(format, text);
        }

        private static void Print<T>(string format, T item)
        {
            Console.WriteLine(format, item);
        }
    }

原文地址:https://www.cnblogs.com/75115926/p/3062290.html