面向对象——泛型类

概念:泛型编程是一种编程方式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的服用,然后使用这些变量记录不同类型的数据,这样可以重复利用泛型来存储不同类型的数据。

       泛型用于处理算法,数据结构的一种编程方法。泛型的目标采用广泛适用和可交互性的形式来表示算法和数据结构,以使他们能够直接用于软件构造。泛型类、结构、接口、委托和方法可以根据他们存储和操作的数据类型来进行参数化。泛型能在编译时提供强大的类型检查,减少数据类型之间的显示转换、装箱操作和运行时的类型检查等。泛型类和泛型方法同时具备可重用性、类型安全和效率高等特性。这是非泛型类和非泛型方法无法具备的。

语法格式如下:

  类修饰符 class 类名<类型参数T>

       {

              类体

}

泛型类的声明比普通类多一个类型参数T,类型参数T乐意看作是一个占位符,他不是一种类型,它仅仅代表了某种可能的类型。在定义泛型类,T出现的位置可以在使用时,用任何类型来代替。类型参数T的命名规则如下:

  • 使用描述名称命名泛型类型参数,除非单个字母名称完全可以让人了解它表示的含义,而面熟性名称不会有更多的意义。
  • 将T作为面熟性类型参数名的前缀。

例:使用泛型存储不同类型的数据列表

namespace ExtensiveList

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

        class Types<T>

        {

            public T Num; //声明编号字段

            public T Name; //声明姓名字段

            public T Sex; //声明性别字段

            public T Age; //声明年龄字段

            public T Birthday; //声明生日字段

            public T Salary; //声明薪水字段

        }

        private void button1_Click(object sender, EventArgs e)

        {

            Types<object> Exte = new Types<object>();//实例化泛型类对象

            //为泛型类中声明的字段进行赋值,存储不同类型的值

            Exte.Num = 1;

            Exte.Name = "王老师";

            Exte.Sex = "男";

            Exte.Age = 25;

            Exte.Birthday = Convert.ToDateTime("1986-06-08");

            Exte.Salary = 1500.45F;

            //将泛型类中各字段的值显示在文本框中

            textBox1.Text = Exte.Num.ToString();

            textBox2.Text = Exte.Name.ToString();

            textBox3.Text = Exte.Sex.ToString();

            textBox4.Text = Exte.Age.ToString();

            textBox5.Text = Exte.Birthday.ToString();

            textBox6.Text = Exte.Salary.ToString();

        }

    }

}

例2:泛型的继承:泛型继承类与普通类是类似的,只是在继承的时候多个T,格式如下:

  class DerivedClass<参数类型T>:BaseClass<参数类型T>

举例:  class BStuInfo<T>

        {

            public T ID; //声明学生编号字段

            public T Name; //声明姓名字段

            public T Sex; //声明性别字段

            public T Age; //声明年龄字段

            public T Birthday; //声明生日字段

            public T Grade; //声明班级字段

        }

        class HStuInfo<T> : BStuInfo<T>//继承自BStuInfo泛型类

        {

            public T Chinese; //声明语文成绩字段

            public T Math; //声明数学成绩字段

            public T English; //声明英语成绩字段

        }

泛型方法是在声明中包括了类型参数T的方法。泛型方法可以在类、结构或接口中声明,这些类、结构或接口本身可以是泛型或非泛型。如果在泛型类型声明中声明泛型方法,则方法可以同时引用该方法的类型参数T和包含该方法声明的类型参数T。泛型方法的语法如下:

[修饰符]  [返回值类型]  [方法名]  <参数类型T>()

{

       方法体

}

例:通过泛型查找不同的值

namespace ArrayInfo

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

        public class Finder

        {

            // 定义一个泛型方法,用来查找指定值在数组中的索引

            public static int Find<T>(T[] items, T item)

            {

                for (int i = 0; i < items.Length; i++)//遍历泛型数组

                {

                    if (items[i].Equals(item))//判断是否找到了指定值

                    {

                        return i;//返回指定值在数组中的索引

                    }

                }

                return -1;//如果没有找到,返回-1

            }

        }

        private void button1_Click(object sender, EventArgs e)

        {

            string[] Str = new string[] { "一", "二", "三", "四", "五", "六", "七", "八", "九" };//声明一个字符串类型的数组

            MessageBox.Show(Finder.Find<string>(Str, "三").ToString());//查找字符串在数组中的索引

        }

        private void button2_Click(object sender, EventArgs e)

        {

            int[] IntArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };//声明一个整数类型的数组

            MessageBox.Show(Finder.Find<int>(IntArray, 5).ToString());//查找数字5在数组中的索引

        }

        private void button3_Click(object sender, EventArgs e)

        {

            bool[] IntArray = new bool[] { true, false};//声明一个布尔类型的数组

            MessageBox.Show(Finder.Find<bool>(IntArray, false).ToString());//查找false在数组中的索引

        }

    }

}

例2: 泛型作为返回值,例如Spring.Net中获取类的方法

       public static T GetObject(string name)

        {

            try

            {

                IApplicationContext ctx = ContextRegistry.GetContext();

                return ctx.GetObject(name) as T;

            }

            catch (Exception ex)

            {

                logger.Error(ex.Message);

                return default(T);

            }

        }

}

泛型方法的重载:与普通的方法类似,只是声明时,添加了一个类型参数T

例:通过泛型实现子窗体的不同的操作。

uploading.4e448015.gif转存失败重新上传取消 namespace FormDisOperate

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

        public void FormOperate<T>()

        {

            Form2 Frm_2 = new Form2();//实例化Form2窗体对象

            Frm_2.ShowDialog();//以对话框形式显示Form2窗体

        }

        public void FormOperate<T>(string strError)

        {//实例化提示框中显示图标对象

MessageBoxIcon messIcon = MessageBoxIcon.Error;            MessageBox.Show(strError, "提示", MessageBoxButtons.OK, messIcon);//显示错误提示框

        }

        private void button1_Click(object sender, EventArgs e)

        {

            FormOperate<object>();//调用FormOperate方法的第一种重载形式对窗体操作

        }

        private void button2_Click(object sender, EventArgs e)

        {

            FormOperate<object>("数据库连接失败。");//调用FormOperate方法的第二种重载形式对窗体操作

        }

    }

}

使用泛型集合:通常情况下,建议开发人员使用泛型集合,因为这样可以获得类型安全的直接优点,而不需要从基集合类型派生并实现类型特定的成员。此外,如果集合元素为值类型,泛型集合类型的性能通常优于对应的非泛型集合类型,并优于从非泛型基集合类型派生的类型,因为使用泛型时不必对元素进行封装。

常用的集合:ArrayList、Hashtable、Stack、Queue。需要添加命名空间using System.Collections

ArrayList使用举例:添加单个元素

static void Main(string[] args)

        {

          ArrayList list=new ArrayList();

            list.Add(12);

            list.Add("ASsa");

            list.Add(false);

            foreach(var i in list)

            {

                Console.WriteLine(i.ToString());

            }

        }

输出结果:

12

ASsa

False

添加数组:

          static void Main(string[] args)

        {

          int[] arr = { 1, 2, 3 };//第一种添加数组的方法

          ArrayList list=new ArrayList();

          list.AddRange(arr);

          int[] arr1 = { 4, 5, 6 };//第二种添加数组的方法

          ArrayList list1 = new ArrayList(arr1);

        }

ArrayList常用的一些方法:

static void Main(string[] args)

        {

          int[] arr = { 1, 2, 3 };

          ArrayList list=new ArrayList();

          list.AddRange(arr);

          list.Clear();//清除所有数据

          list.Contains(2);//判断是否包含这个数据,包含输出true,不包含输出false

          int cap = list.Capacity;//得到目前最大容量

          int num = list.Count;//得到实际元素的个数

          int b = list.Count;//返回元素的下标,从左向右查

          list.Insert(0, 12);//在下边为0处插入12,其后面的,后移一位,下标不能超过list的最大长度

          list.Remove(2);//删除一个元素,存在则删除,不存在就不执行。

          list.RemoveAt(0);//删除下标的元素,括号为下标

        }

HashTable常用的方法:

   static void Main(string[] args)

        {

            Hashtable table = new Hashtable();

            table.Add("1", 10);

            table.Add("2", 20);

            table.Add("3", 30);//添加数据

            object i = table["1"];//根据Key,获取对应的Value

            table.Clear();//删除表

            bool key = table.Contains("1");//是否包含某个键,若包含则返回true

            bool key1 = table.ContainsKey("1");//是否包含某个键,若包含则返回true

            bool val = table.ContainsValue(10);//是否存在10.存在返回true

            int ct = table.Count;//返回元素的个数

            ICollection ic = table.Keys;//获取所有的键值

            foreach (object o in ic)

            {

                Console.WriteLine(0);//结果:1,2,3

            }

            ic = table.Values;

            foreach (object o in ic)

            {

                Console.WriteLine(o);//结果:102030

            }

            foreach (DictionaryEntry d in table)

            {

                Console.WriteLine("{0},{1}",d.Key,d.Value);

            }

        }

//结果:

              //1,10

              //2,20

              //3,30

栈是一种先进后出的一种数据结构,类似口向上的井

栈举例:

                 Stack st = new Stack();

            st.Push(1);

            st.Push(2);//压栈

            object o = st.Pop();//出栈,并把栈顶删除

            object ob = st.Peek();//出栈,并不删除栈顶元素

队列是一种先进先出的数据结构

队列举例:   Queue q = new Queue();

            q.Enqueue(1);

            q.Enqueue(2);//添加数据

            object o = q.Dequeue();//出队,并把队顶元素删除

            object ob = q.Peek();//出队,并不删除队顶元素

常用的泛型:

  • List<数据类型>

格式:List<s数据类型> list=new List<数据类型>();取代了集合中的ArrayList

  • Dictionary<数据类型,数据类型>

格式:Dictionary<数据类型,数据类型> dic=new Dictionary<数据类型,数据类型>();取代了集合中的HashTable

  • Stack<数据类型>

格式Stack<数据类型> s=new Stack<数据类型>();取代了集合中Stack

  • Queue<数据类型>

格式Queue <数据类型> s=new Queue <数据类型>();取代了集合中Queue

举例:从字典中同时取出,key和对应的value

Dictionary<int, string> dic = new Dictionary<int, string>();

           dic.Add(1, "10");

           dic.Add(2, "20");

           string s = dic[1];//取出key为1的值。

           Dictionary<int, string>.KeyCollection keys = dic.Keys;//获取所有的键值

           foreach (int i in keys)//遍历Key

           {

                Console.WriteLine(i);

           }

          Dictionary<int, string>.ValueCollection vals = dic.Values;//获取所有的Value值

           foreach (string t in vals)//遍历Value

            {

                Console.WriteLine(t);

            }

            foreach (KeyValuePair<int, string> k in dic)//遍历键值对

            {

                Console.WriteLine(k.Key+"....."+k.Value);

            }

字典和List嵌套综合应用:字典中嵌套List,按字典的key进行分类放入List中。比如按照名字进行分类

private void BindGrid()

{

       List<MemberInfo> memberList=_bll.getList();//获取数据放入列表

Dictionary<string,List<MemberInfo>> memberNameDic=new Dictionary<string,List<MemberInfo>>();//建立嵌套List

Foreach(Member memberInfo in memberList)

{

       if(memberNameDic.ContainsKey(memberInfo.MemberName)==false)    

{

       memberNameDic.Add(memberInfo.MemberName , new List<MemberInfo>())

}

memberNameDic[memberInfo.MemberName].Add(memberInfo);//向字典中按姓名相同进行分类

}

Foreach( string key in memberNameDic.Keys)

{

       GroupNameSame(key , memberNameDic[key]);

}

}

Private void GroupNameSame(string name,IList<MemberInfo> memberNameList)

{

       Foreach(MemberInfo memberInfo in memberNameList)

{}//读取List

}

泛型排序列表,SortList<Tkey,TValue> 表示按照键进行的排序的键/值对的集合,键/值对是KeyValuePair<TKey,TValue>类型。泛型排序列表具有以下3个特点:

  1. 、将添加到泛型排序的表的元素自动按照键进行排序。
  2. 、泛型排序列表中的键不能修改,不能为空,不能重复。
  3. 、泛型排序列表的值乐意修改,可以为空,可以重复。

  public class UserInfo

    {

        public int UserCode { get; set; }

        public string UserName { get; set; }

        public string PassWord { get; set; }

        public UserInfo(int userCode, string userName, string passWord)

        {

            UserCode = userCode;

            UserName = userName;

            PassWord = passWord;

        }

    }

    class Program

    {    

        static void Main(string[] args)

        {

            SortedList<int, UserInfo> uses = new SortedList<int, UserInfo>();

            uses.Add(2, new UserInfo(2, "User02", "02"));

            uses.Add(3, new UserInfo(3, "User03", "03"));

            uses.Add(1, new UserInfo(1, "User01", "01"));

            foreach (var item in uses)

            {

                Console.WriteLine("{0},{1}",item.Key,item.Value.UserName);

            }//按照key的顺序从小到大排序

        }

    }

输出结果:

1,User01

2,User02

3,User03

利用比较器来定义排序规则,将排序规则改为大到小顺序:

    public class ListComparer : IComparer<int>

    {

        #region IComparer<int> 成员

        public int Compare(int x, int y)

        {

            if (x > y)

            {

                return -1;

            }

            else

            {

                return 1;

            }

        }

        #endregion

    }

    public class UserInfo

    {

        public int UserCode { get; set; }

        public string UserName { get; set; }

        public string PassWord { get; set; }

        public UserInfo(int userCode, string userName, string passWord)

        {

            UserCode = userCode;

            UserName = userName;

            PassWord = passWord;

        }

    }

    class Program

    {    

        static void Main(string[] args)

        {

            SortedList<int, UserInfo> uses = new SortedList<int, UserInfo>(new ListComparer());

            uses.Add(2, new UserInfo(2, "User02", "02"));

            uses.Add(3, new UserInfo(3, "User03", "03"));

            uses.Add(1, new UserInfo(1, "User01", "01"));

            foreach (var item in uses)

            {

                Console.WriteLine("{0},{1}",item.Key,item.Value.UserName);

            }

        }

    }

输出结果:

3,User03

2,User02

1,User01

泛型排序字典

SortedDictionary<string, string> sortDic = new SortedDictionary<string, string>();

            sortDic.Add("qw", "1qwa");

            sortDic.Add("as", "sdfsa");

            foreach (var i in sortDic.Keys)

            {

                Console.WriteLine(i.ToString());

            }//默认按照字典序排序、

输出结果:

as

qw

 

  1. IListList的区别

首先IList 泛型接口是 ICollection 泛型接口的子代,并且是所有泛型列表的基接口。它仅仅是所有泛型类型的接口,并没有太多方法可以方便实用,如果仅仅是作为集合数据的承载体,确实,IList可以胜任。

其次, IList <> 是在 .net framework 2.0里面才支持的

1. 不过,更多的时候,我们要对集合数据进行处理,从中筛选数据或者排序。这个时候IList就不太好使了。因为他的效率要慢。后面会一一讲到。

2IList <>是个接口,定义了一些操作方法这些方法要你自己去实现,List <>是泛型类,它已经实现了IList <>定义的那些方法
IList IList11 =new List ();
List List11 =new List ();

这两行代码,从操作上来看,实际上都是创建了一个List对象的实例,也就是说,他们的操作没有区别。只是用于保存这个操作的返回值变量类型不一样而已。
那么,我们可以这么理解,这两行代码的目的不一样。
List List11 =new List ();
是想创建一个List,而且需要使用到List的功能,进行相关操作。
IList IList11 =new List ();
只是想创建一个基于接口IList的对象的实例,只是这个接口是由List实现的。所以它只是希望使用到IList接口规定的功能而已。

3.接口实现松耦合...有利于系统的维护与重构...优化系统流程...鼓励使用接口,这样可以实现功能和具体实现的分离.

 这些说的都是有道理的,那么接刚才第一点的话题说,为什么说用到数据处理,或者排序IList就不太好使了呢。这个也是要根据数据量来的。我做了如下测试

        public class TestClass
        {
            public int Id
            {  get;  set; }
            public string Name
            { get; set;}
        }

        static void Main(string[] args)
        {
            ListTest();
        }

        private static void ListTest()
        {
            Stopwatch timer = new Stopwatch();
            timer.Start();
            List<TestClass> list1 = new List<TestClass>();
            for (int i = 0; i < 10000000; i++)
            {
                TestClass tc = new TestClass();
                tc.Id = i;
                tc.Name = "Test Data" + i;
                list1.Add(tc);
            }
            int count = 0;
            foreach (var tc in list1)
            {
                if (tc.Id >= 1 && tc.Id < 1000)
                {
                    count++;
                }
            }
            //list1.OrderBy(i => i.Id);
            timer.Stop();
            Console.Write("Count:" + count + ", List time:");
            Console.WriteLine(timer.Elapsed.Ticks);
            timer = new Stopwatch();
            timer.Start();
            IList<TestClass> list2 = new List<TestClass>();
            for (int i = 0; i < 10000000; i++)
            {
                TestClass tc = new TestClass();
                tc.Id = i;
                tc.Name = "Test Data" + i;
                list2.Add(tc);
            }
            int count2 = 0;
            foreach (var tc in list2)
            {
                if (tc.Id >= 1 && tc.Id < 1000)
                {
                    count2++;
                }
            }
            //list2.OrderBy(i => i.Id);
            timer.Stop();
            Console.Write("Count:" + count2 + ", IList time:");
            Console.WriteLine(timer.Elapsed.Ticks);
            Console.Read();
        }

当我们都去遍历IListList的时候,注意我取的数据是1~1000之间,经过反复测试,IList的效率确实是要低一些。那就更不用说数据量更大的时候,请看输出框:

  uploading.4e448015.gif转存失败重新上传取消

但是,当我取的数据是1~500的时候, IList似乎效率还是要慢一些。

 另外,可能有的朋友会说,你把前面的for循环放在外面比较呢,这个我也做过测试,结果还是一样,List效率要好于IList

同样的方法,我测试了,IListListOrderBy的效率,List均有胜面,高效一筹。所以,什么时候用IListList自己去斟酌,当你用到设计的时候当然是IList合理一些。用做数据容器遍历或者排序,还是选择List好一点。

数组、ArrayListList区别:

      数组

    数组在C#中最早出现的。在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也很简单。

    但是数组存在一些不足的地方。在数组的两个数据间插入数据是很麻烦的,而且在声明数组的时候必须指定数组的长度,数组的长度过长,会造成内存浪费,过段会造成数据溢出的错误。如果在声明数组时我们不清楚数组的长度,就会变得很麻烦。

    针对数组的这些缺点,C#中最先提供了ArrayList对象来克服这些缺点。

ArrayList

    ArrayList是命名空间System.Collections下的一部分,在使用该类时必须进行引用,同时继承了IList接口,提供了数据存储和检索。ArrayList对象的大小是按照其中存储的数据来动态扩充与收缩的。所以,在声明ArrayList对象时并不需要指定它的长度。

ArrayList中插入不同类型的数据是允许的。因为ArrayList会把所有插入其中的数据当作为object类型来处理,在我们使用ArrayList处理数据时,很可能会报类型不匹配的错误,也就是ArrayList不是类型安全的。在存储或检索值类型时通常发生装箱和取消装箱操作,带来很大的性能耗损。

泛型List

    因为ArrayList存在不安全类型与装箱拆箱的缺点,所以出现了泛型的概念。List类是ArrayList类的泛型等效类,它的大部分用法都与ArrayList相似,因为List类也继承了IList接口。最关键的区别在于,在声明List集合时,我们同时需要为其声明List集合内数据的对象类型。

比如:

List<string> list = new List<string>(); 

list.Add(“abc”);  //新增数据

list[0] = “def”;   //修改数据

list.RemoveAt(0);  //移除数据

    上例中,如果我们往List集合中插入int数组123IDE就会报错,且不能通过编译。这样就避免了前面讲的类型安全问题与装箱拆箱的性能问题了。

总结:

    数组的容量是固定的,您只能一次获取或设置一个元素的值,而ArrayListList<T>的容量可根据需要自动扩充、修改、删除或插入数据。

    数组可以具有多个维度,而 ArrayList List< T> 始终只具有一个维度。但是,您可以轻松创建数组列表或列表的列表。特定类型(Object 除外)的数组 的性能优于 ArrayList的性能。 这是因为 ArrayList的元素属于 Object 类型;所以在存储或检索值类型时通常发生装箱和取消装箱操作。不过,在不需要重新分配时(即最初的容量十分接近列表的最大容量),List< T> 的性能与同类型的数组十分相近。

    在决定使用 List<T> 还是使用ArrayList 类(两者具有类似的功能)时,记住List<T> 类在大多数情况下执行得更好并且是类型安全的。如果对List< T> 类的类型T 使用引用类型,则两个类的行为是完全相同的。但是,如果对类型T使用值类型,则需要考虑实现和装箱问题。

C# 集合性能 总结                          标记说明:

  1. O(1) 表示无论集合中有多少项,这个操作需要的时间都不变,例如,ArraryLIst的Add(方法就O(1),无论集合中有多少元素,在列表尾部添加一个新的元素的时间都是相同的.
  2. O(n)表示对于集合中的每个元素,需要增加的时间量都是相同的,如果需要重新给
  3. O(log n)表示操作需要的时间随着集合中元素的增加和增加,但每个元素增加的时间不是线性的.而是呈对数曲线,在集合中插入操作时,SortedDictionary<Tkey,Tvalue>就是O(log n),而SortedList<Tkey,Tvalue> 就是O(n),这里SortedDictionary<Tkey,Tvalue>要快的多.因为它在树形结构中插入元素的效率比列表高的多.下表显示各种集合的操作时间:

集合

Add

Insert

Remove

Item

Sort

Find

List<T>

如果集合必须重置大小就是O(1)或O(n)

O(n)

O(n)

O(1)

O(n log n)最坏情况O(n^2)

O(n)

Stack<T>(栈)

Push(),如果栈必须重置大小,就是O(1)或O(n)

no

Pop(),O(1)

no

no

no

Queue<T>(列队)

Enqueue(),如果栈必须重置大小,就是O(1)或O(n)

no

Dequeu(),O(1)

no

no

no

HastSet<T>(无序列表)

如果栈必须重置大小,就是O(1)或O(n)

Add()

O(1)或O(n)

O(1)

no

no

no

LinkedList<T>(链表)

AddLast(),O(1)

AddAfter(),O(1)

O(1)

no

no

O(n)

Dictionary<Tkey,TValue>

O(1) 或 O(n)

no

O(1)

O(1)

no

no

SortedDictionary<Tkey,Tvalue>

O(log n)

no

O(log n)

O(log n)

no

no

SortedList<Tkey,Tvalue>

无序数据为O(n),如果必选重置大小,到列表的尾部就是

O(log n)

no

O(n)

读写是O(log n),如果键在列表中,就是O(log n),如果键不在列表中就是O(n).

no

no

 

  :如果单元格中有多个大O,表示集合需要重置大小,该操作需要一定的时间

      如果单元格内容是no,就表示不支持这种操作.

 小结:

     数组的大小是固定的,但可以使用列表作为动态增长集合,列队以先进先出的方式访问元素,栈以后进先出的方式访问元素,

链表可以快速的插入和删除元素,但搜索比较慢,通过键和值可以使用字典,它的搜索和插入操作比较快,(Hashset<T>) 是用于无序的唯一项.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

可观察集合

如果需要集合中的元素合适删除或添加的信息,就可以使用ObserVableCollection<T>类。这样UI就可以知集合的变化。这个类的名命空间SystemCollections.ObjectModel.

ObserableCollection<T>类派生自Collection<T>积累。该基类可以用于创建自定义集合,并在内部使用List<T>类。重写了基类中的虚方法SetITem()和RemoveItem(),以出发CollectionChanged事件。这个类的用户可以使用InotifyCollectionChanged接口注册事件。

using System.Collections.ObjectModel;

namespace Wrox.ProCSharp.Collections

{

    class Program

    {

        static void Main()

        {

            var data = new ObservableCollection<string>();

            data.CollectionChanged += Data_CollectionChanged;

            data.Add("One");

            data.Add("Two");

            data.Insert(1, "Three");

            data.Remove("One"); 

        }

        static void Data_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

        {

            Console.WriteLine("action: {0}", e.Action.ToString());

            if (e.OldItems != null)

            {

                Console.WriteLine("starting index for old item(s): {0}", e.OldStartingIndex);

                Console.WriteLine("old item(s):");

                foreach (var item in e.OldItems)

                {

                    Console.WriteLine(item);

                }

            }

            if (e.NewItems != null)

            {

                Console.WriteLine("starting index for new item(s): {0}", e.NewStartingIndex);

                Console.WriteLine("new item(s): ");

                foreach (var item in e.NewItems)

                {

                    Console.WriteLine(item);

                }

            }

            Console.WriteLine();

        }

    }

}

输出结果:

action: Add

starting index for new item(s): 0

new item(s):

One

 

action: Add

starting index for new item(s): 1

new item(s):

Two

 

action: Add

starting index for new item(s): 1

new item(s):

Three

 

action: Remove

starting index for old item(s): 0

old item(s):

One

 

发布了48 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/hhhhhhhhhhwwwwwwwwww/article/details/105504291
今日推荐