面向对象——泛型类

简介: 面向对象——泛型类

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


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


语法格式如下:


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


      {

             类体


}


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


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

将T作为面熟性类型参数名的前缀。


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


tt.png

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>()


{

      方法体


}


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


tt.png

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


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

tt.png

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);//结果:10、20、30


           }


           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个特点:


、将添加到泛型排序的表的元素自动按照键进行排序。

、泛型排序列表中的键不能修改,不能为空,不能重复。

、泛型排序列表的值乐意修改,可以为空,可以重复。

 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



IList和List的区别

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


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


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


2、IList <>是个接口,定义了一些操作方法这些方法要你自己去实现,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();

       }


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


tt.png

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


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


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


数组、ArrayList、List区别:


     数组


   数组在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数组123,IDE就会报错,且不能通过编译。这样就避免了前面讲的类型安全问题与装箱拆箱的性能问题了。


总结:


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


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


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


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

O(1) 表示无论集合中有多少项,这个操作需要的时间都不变,例如,ArraryLIst的Add(方法就O(1),无论集合中有多少元素,在列表尾部添加一个新的元素的时间都是相同的.

O(n)表示对于集合中的每个元素,需要增加的时间量都是相同的,如果需要重新给

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


 



tt.pngtt.png

目录
相关文章
|
4月前
|
C#
C# 面向对象编程(三)——接口/枚举类型/泛型
C# 面向对象编程(三)——接口/枚举类型/泛型
36 0
|
4月前
|
Java C# 索引
C# 面向对象编程(一)——类
C# 面向对象编程(一)——类
35 0
|
4月前
|
C# 索引
C# 面向对象编程(二)——继承
C# 面向对象编程(二)——继承
43 0
|
算法 Java 编译器
类和面向对象
类和面向对象
110 0
|
Java
Java语法之多态
上次给大家分享了Java的继承,今天小编给大家分享面向对象三大特性的第三大特性,也就是多态,fighting~~
84 0
Java语法之多态
|
Java
Java语法之继承(上)
上次给大家分享了Java的封装,今天小编给大家分享面向对象三大特性的第二大特性,也就是继承,fighting~~
95 0
|
Java C++
Java语法之继承(下)
上次给大家分享了Java的封装,今天小编给大家分享面向对象三大特性的第二大特性,也就是继承,fighting~~
81 0
|
SQL 安全 数据库
对面向对象继承的一些思考
本文浅谈对面向对象继承的一些思考
132 0
对面向对象继承的一些思考