一、c#中的特殊数据类型
C#中特殊数据类型有class类型、结构类型、数组类型、枚举类型、集合类型、委托类型、事件、Lambda表达式、接口类型。
1、class类型
1.1类定义
class Student : person//继承 { //默认构造函数,vs IDE中输入ator+tab两下可自动生成构造函数代码段 public Student() { //给字段赋值等初始化操作 } //自定义构造函数,b为可选参数 public Student(int a, string b = 5) { //初始化操作 } public Student(int a)//自定义构造函数 { //初始化操作 } //静态构造函数-安全的给静态字段赋值且只能被定义一个(采用普通构造函数每次实例化类对象时静态字段的值会被重置) static Student{aCuu=0.04}//不允许访问修饰符,不接受参数 //static关键字用来定义静态成员,这些成员只能通过类级别而不是对象引用调用。 //static关键字,静态字段由所有类实例共享 public static double aCuu = 0.04; public string petName;//字段,最好定义成私有的以保护 public void Name(string name) { }---方法 } //静态类-只包含静态成员,不能够使用new(分配新内存)关键字来创建类对象-适合做工具类 static class Student { }
1.2访问修饰符
类型成员隐式私有的,而类是隐式内部的。
private、protected、protected internal访问修饰符可以应用到嵌套类型上,非嵌套类型只能用public internal修饰符定义。
public | 可以从对象、派生类、外部其它程序集访问 |
private | 定义类访问 |
protected | 定义类及子类可以访问,外部类无法通过点操作符访问 |
internal | 只能在当前程序集中访问 |
protected internal | 在定义该项的程序集、类及派生类中可用 |
1.3 this 关键字
提供对当前类实例的访问。
串联构造函数,使类更容易维护和简明。
class Motorcycle { public int driverIntensity; public string drivername; //构造函数 public Motorcycle(){} public Motorcycle(int intensity) : this(intensity, "") { } public Motorcycle(string name):this(0,name) { } //所有工作的主构造函数 public Motorcycle(int intensity,string name) { //操作 } }
2、结构类型
结构类型可以看成是轻量级的类类型,但是不能像类一样继承
struct point { //字段 public int x; //方法 public void Increment() { } } //创建结构变量 point p1; p1.x = 5;//需要为每一个共有字段成员赋值 point p2 = new point();
3、数组类型
一组相同类型的数据点:int[] myInt=new int[3]
int[] myInt=new int[3]{1,2,3} #初始化
3.1 特殊数组
隐式数组 | var a=new[]{1,2,3} |
object数组 | object[] myob=new[3]{1,"string",new DateTime(2017,8,28)} |
多维数组 | int[,] myArray=new int[6,6] |
4、枚举类型
System.Enum类中包含有一些对枚举类型操作的方法
enum Emptype:Byte { manager=12,//=0,可任意,可不连续 student, teancher } Emptype ee = Emptype.manager; Enum.GetUnderlyingType(ee.GetType());//返回枚举类型值的数据类型 Console.WriteLine(ee.ToString());//获取枚举名字 Console.WriteLine((Byte)ee);//根据底层类型强制转换获取其数值 Array enumData = Enum.GetValues(ee.GetType());//获取所有枚举值 Console.WriteLine("this enum has {0} nums:", enumData.Length); Console.WriteLine("name{0};value{1}", enumData.GetValue(1));
5、集合类型-数据容器
System.Collections与System.Collection.Generic命名空间
简单数组通常是固定大小的,而集合类本身的尺寸是动态的,类似于python中的list类型,很多集合提供了更强的类型安全,进行了高度优化,可以以内存高效的方式处理所包含的数据。
集合可划分为两大种类:非泛型集合和泛型集合
5.1泛型集合System.Collections常用类
ArrrayList | 动态大小对象集合,对象按顺序列出 | Ilist/Icollection/IEnumerable/ICloneable |
BitArray | 管理位值的简单数组,位值bool类型 | ICollection/IEnumerable/ICloneable |
Hashtable | 表示键值对的集合 | IDictionary/Icollection/IEnumerable/ICloneable |
Queue | FIFO队列 | ICollection/IEnumerable/ICloneable |
SortedList | 键值对集合按键排序 | IDictionary/Icollection/IEnumerable/ICloneable |
Stack | 后进先出 | ICollection/IEnumerable/ICloneable |
System.Collections中类所支持的关键接口
ICollection | 为所有非泛型集合定义基本特性(大小、枚举、线程安全) |
ICloneable | 允许实现它的对象向调用者返回它的副本 |
IDictionary | 非泛型集合使用键值对表示其内容 |
IEnumerable | 返回实现了IEnumerable接口的对象 |
IEnumerator | 允许子类型以foreach形式迭代 |
IList | 为顺序列表中的对象提供添加、移除和索引项的行为 |
示例代码:
class Program { static void Main(string[] args) { ArrayList list = new ArrayList(); //集合:很多数据的一个集合 //数组:长度不可变、类型单一 list.Add(true); list.Add(1); list.Add(2); list.Add("张三"); Person person = new Person(); list.Add(person); list.Add(new int[] { 1, 2, 3 }); list.AddRange(list); list.AddRange(new int[] { 234, 23432 });//此种方法可以直接输出 for(int i=0; i<list.Count; i++) { if(list[i] is Person ) { ((Person)list[i]).SayKello(); } else if(list[i] is int[]) { for(int j=0;j<((int[])list[i]).Length;j++) { Console.WriteLine(((int[])list[i])[j]); } } //麻烦 else { Console.WriteLine(list[i]); } } Console.ReadKey(); //List元素打印出来的是所在类对应的命名空间 } class Person { public void SayKello() { Console.Write("你好"+" "); } } }
//其他类的用法类似,有相应的文档
HashTable示例:
static void Main(string[] args) { //键值对集合类似于字典,根据键去找值,就像根据拼音去找汉字 Hashtable ht = new Hashtable(); ht.Add(1,"张三"); ht.Add(2,"小王"); ht.Add(false,"错误的"); for (int i = 0; i < ht.Count; i++) { object a = ht[i]; Console.WriteLine(a); } //不能全部显示(0和false) Console.ReadKey(); Console.WriteLine(ht[false]); //也可以采用foreach循环遍历 foreach (var item in ht.Keys) { //C#是一门强类型语言:代码中每一个变量类型必须有明确的定义 //int n = 15; //string ste = "sfdd"; //bool n5 = true; //double n6 = 230.23; //Console.WriteLine(n.GetType()); //Console.WriteLine(ste.GetType()); //Console.WriteLine(n5.GetType()); //Console.WriteLine(n6.GetType()); //Console.ReadKey(); //根据值推断出类型 //var n = 15; //var ste = "sfdd"; //var n5 = true; //var n6 = 230.23; //Console.WriteLine(n.GetType()); //Console.WriteLine(ste.GetType()); //Console.WriteLine(n5.GetType()); //Console.WriteLine(n6.GetType()); //Console.ReadKey(); //var input; 声明var变量的时候必需给它赋值 //input = "人民"; Console.WriteLine(ht[item]); } Console.ReadKey(); }
5.2非泛型集合
相比较于泛型集合,非泛型集合更为常用,经典的泛型集合常常存在如下问题:
1)频繁的装箱拆箱操作,当数据量过大时会降低程序效率:
.NET包含一个特殊的Object类,可以接受任意的数据类型的值,当所传递或所赋值的类型不是一个特定的数据类型时,object类就提供了一种传递参数和赋值的通用方法。赋给object的值必须作为引用类型,并存放砸托管堆中,简言之装箱就是值类型转换为引用类型;拆箱就是引用类型转换为值类型。
值类型:包括原类型(Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚举 (enum) 、结构 (struct)。
引用类型:包括类、数组、接口、委托、字符串等
一下特殊情况需要注意:
隐式转换总会成功的情况 | 显式引用转换可能会抛出异常的情况 |
从派生类到基类 | 从基类到派生类 |
从派生接口到基接口 | 从接口到接口(基接口到派生接口或者俩接口没有关系) |
从类到接口(该类实现了接口) | 从接口到类(该类实现了该接口或该类未封闭) |
从Null到任何类 | 从类到接口(该类未实现该接口且该类未封闭) |
class Program { int a = 3; object ob = a;//装箱操作 int b = (int)ob;//拆箱操作 }
2)类型安全问题,所有的类型都可以转换成object类,在特定的情况下存在类型安全问题。
5.3泛型集合
只有类、结构、接口和委托可以使用泛型,枚举类型不可以。
1)System.Collection.Generic命名空间
2)初始化语法
class Point { int x; int y; public Point(int x, int y) { this.x = x; this.y = y; } } class Program { static void Main(string[] args) { List<Point> myOfpoint = new List<Point> { new Point(1,2), new Point(3,4) }; } }
3)List<T>类
常见用法见:http://www.cnblogs.com/AdaLoong/p/5528917.html
4)Stack<T>类---后进先出
包含Push和Pop方法,可以向栈中压入数据或弹出数据,在观察栈时得到的永远是栈顶对象,可以通过调用peek()来显示。
http://www.cnblogs.com/deom/p/5349317.html
5)Queue<T>类---先进先出
http://www.cnblogs.com/jiahuafu/archive/2013/01/05/2845640.html
Dequeue()---移除并返回开始出的对象;
Enqueue()---在末未添加一对象;
peek()---返回开始出的对象但是不移除。
6)SortedSet<T>类---自动排序
必须通知SortedSet<T>类按照何种方式排序,可以向其构造函数传递一个实现了IComparer<T>泛型接口的参数,比如一个实现了该泛型接口的类。
http://blog.sina.com.cn/s/blog_621e24e20100zqmq.html
class sortByage:IComparer<Person> { public int Compare(Person firstperson,Person secondperson) { if (firstperson.age > secondperson.age) return 1; if (firstperson.age < secondperson.age) return -1; else return 0; } } class Person { string firstname; string lastname; public int age; public Person(string firstname,string lastname,int age) { this.firstname = firstname; this.lastname = lastname; this.age = age; } } static void Main(string[] args) { SortedSet<Person> mysortedOfperson = new SortedSet<Person>(new sortByage()) { new Person("wangming","zhang",112), new Person("xiaogang","wang",13), new Person("xiaohong","li",56) }; //按照年龄排序 foreach (Person p in mysortedOfperson) { Console.WriteLine(p.age); } Console.ReadKey(); }
7)System.Collections.ObjectModel命名空间
该命名空间也是以泛型为核心
两个比较有用的类
ObservableCollection<T> | 表示能在添加、移除项或者刷新整个列表时提供通知的动态数据集合 |
ReadOnltObservableCollection<T> | 表示ObservableCollection<T>的只读版本 |
ObservableCollection<T>与List<T>具有相同的核心接口,不同的是ObservableCollection<T>实现了名为CollectionChanged的事件,该事件在添加、移除项或者刷新整个列表时触发。
CollectionChanged定义为委托,该委托可以调用一类方法(第一个参数为object,第二个参数为NotifyCollectionChangedEventArgs)。
class Program { static void Main(string[] args) { ObservableCollection<Person> mysortedOfperson = new ObservableCollection<Person>() { new Person("wangming","zhang",112), new Person("xiaogang","wang",13), new Person("xiaohong","li",56) }; //按照年龄排序 //绑定collentionchanged事件 mysortedOfperson.CollectionChanged += people_collentionchanged; mysortedOfperson.Add(new Person("jfoda", "ad", 12)); Console.ReadKey(); } static void people_collentionchanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { //触发事件的行为是什么 Console.WriteLine("Action for this event:{0}", e.Action); if(e.Action==System.Collections.Specialized.NotifyCollectionChangedAction.Add) { Console.WriteLine("here are the new item:"); foreach (Person p in e.NewItems) { Console.WriteLine(p.ToString()); } } } } class Person { string firstname; string lastname; public int age; public Person(string firstname,string lastname,int age) { this.firstname = firstname; this.lastname = lastname; this.age = age; } }
6、委托类型delegate
委托类型用来定义和响应应用程序中的回调,使用回调程序员可以使用一个函数返回报告给程序中的另一个函数,使用这种方法,windows开发者可以可以处理按钮单击、鼠标移动、菜单选择以及内存中两个实体的双向通信。本质上委托是个类型安全的对象,它指向一个以后会被调用的方法(或者多个方法),可以不用手工创建一个thread对象去条用其它thread上的方法,委托类型有三个重要的信息:
1)它所调用的方法和名称
2)该方法的参数(可选)
3)该方法的返回值类型(可选)
6.1、委托类型的定义
public delegate int BinaryOp(int x,int y)
使用delegate关键字,就间接创建了一个类,这个类是“MulticastDelegate”,下表显示了所有委托对象都有的核心成员。
例1:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 委托简例 { public delegate int BinaryOp(int x, int y); //创建一个包含委托指向方法的类 public class SimpleMath { public int Add(int x, int y) { return x + y; } } class Program { //显示委托对象所维护的方法名称及对应的类名称 static void DisplayDelegateInfo(Delegate delObj) { //输出委托调用列表中每个成员的名称 foreach (Delegate d in delObj.GetInvocationList()) { Console.WriteLine("Method name:{0}", d.Method); Console.WriteLine("Type name:{0}", d.Target); } Console.ReadKey(); } static void Main(string[] args) { //实例化一个委托对象 BinaryOp bp = new BinaryOp(new SimpleMath().Add);//指向的是非静态方法要生成实例 //BinaryOp bp = new BinaryOp(SimpleMath.Add);//指向的是静态方法则不需要,只需给出内存地址即可 Console.WriteLine("10+10={0}", bp(10, 10)); Console.ReadKey(); DisplayDelegateInfo(bp); } } }
例2
//声明委托 public delegate void Mydel(); public delegate void Mydel2(int num1, int num2); public delegate string Mydel3(string s); //声明委托用于演示匿名方法 public delegate string ProcessString(string S); class Program { static void Main(string[] args) { TestDel t = new TestDel(); #region 简单实例化委托与调用委托 Console.WriteLine("------以下是简单使用委托演示----"); t.MyMethod(); //实例化委托,用一个方法实例化 //该方法签名要与委托签名一致 Mydel del0 = new Mydel(t.MyMethod); //调用委托 del0(); //另一种实例化方法 Mydel del1 = t.MyMethod; del1(); //用静态方法进行实例化 del1 = TestDel.MyStaticMethod; del1(); //以下代码效果相同 //类TestDel中重载了多种MyMethod方法,委托自动识别一致参数类型的方法 Mydel2 del2 = new Mydel2(t.MyMethod); del2(10,20); Mydel2 del121 = t.MyMethod; del121(10, 20); Mydel3 del3 = new Mydel3(t.MyMethod); del3("adfa"); #endregion #region 匿名实例化weit Console.WriteLine("-----以下是匿名调用委托--"); //用匿名方法实例化委托,不需函数名,直接就是参数+函数体 ProcessString p = delegate(string inputString) { return inputString.ToUpper(); }; //通过委托调用匿名方法 Console.WriteLine(p("wefewe")); #endregion #region 委托多播演示 Console.WriteLine("---------以下是多播演示--------"); Mydel mydel1 = t.MyMethod; Mydel mydel2 = t.MyMethod2; Mydel mydel3 = TestDel.MyMethod3; //委托类型必须一致才能相加 Mydel allmydel = mydel1 + mydel2 + mydel3; allmydel(); allmydel -= mydel3; allmydel(); #endregion #region 委托作为参数演示 Console.WriteLine("-------以下委托作为参数演示--------"); Mydel3 paraMydel3 = t.MyMethod; TestDel.MyParamMethod("aaa", paraMydel3); #endregion #region 委托作为返回值 Console.WriteLine("----以下委托作为返回值演示-----"); //returnMydel指向ReturnMyMethod的返回值 Mydel3 returnMydel = t.ReturnMyMethod(); //returnMydel1指向t.MyMethod Mydel3 returnMydel1 = t.MyMethod; Console.WriteLine(returnMydel("sssssss")); #endregion } } public class TestDel { #region 普通方法 public static void MyStaticMethod() { Console.WriteLine("My Static Method"); } public void MyMethod() { Console.WriteLine("MyMethod"); } public void MyMethod2() { Console.WriteLine("My Method 22222222222"); } public static void MyMethod3() { Console.WriteLine("My Method 3333333333333"); } public void MyMethod(int num1, int num2) { Console.WriteLine(num1 + num2); } public string MyMethod(string s) { return s.ToUpper(); } #endregion /// <summary> /// 委托作为方法参数 /// </summary> /// <param name="s"></param> /// <param name="del3"></param> public static void MyParamMethod(string s, Mydel3 del3) { Console.WriteLine(del3(s)); } /// <summary> /// 委托作为返回值 /// </summary> /// <param name="s"></param> /// <returns></returns> public Mydel3 ReturnMyMethod() { ///返回符合委托规范的方法 return MyMethod; } }
6.2使用委托发送对象通知状态
类似于通过回调函数返回状态信息
namespace 委托通知 { //使用委托来定义car类,他可以通知外部实体当前引擎状态 /// <summary> /// (1)定义将通知发送给调用者的委托类型 /// (2)声明car类中每个委托类型的成员变量 /// (3)在car上创建副主函数使得调用者能指定由委托成员变量保存的方法 /// (4)修改Accelerate()方法以在适当的情形下调用委托的调用列表 /// </summary> public class Car { //内部状态数据 public int CurentSpeed; public int MaxSpeed; public string name; //汽车能不能用 private bool carIsdead; //类构造函数 public Car() { } public Car(string name,int currentspeed,int maxspeed=100) { this.name = name; this.CurentSpeed = currentspeed; this.MaxSpeed = maxspeed; } //定义委托类型 public delegate void CarEngineHandler(string msdForCar); //定义每个委托类型的成员变量 private CarEngineHandler listOfhandlers; //向调用者添加注册函数 public void RegisterWithCarEngine(CarEngineHandler methodTocall) { if (listOfhandlers == null) listOfhandlers = methodTocall; else listOfhandlers += methodTocall;//支持多路广播 } //实现Accelerate()方法 public void Accelerate(int delta) { if(carIsdead) { if(listOfhandlers!=null) { listOfhandlers("sorry,this car is dead"); } } else { CurentSpeed += delta; //不能超过最大速度 if(5==(MaxSpeed-CurentSpeed) && listOfhandlers != null) { listOfhandlers("this speed is nearly to the maxspeed"); } if (CurentSpeed > MaxSpeed) { carIsdead = true; } else Console.WriteLine("current speed:{0}", CurentSpeed); } } } class Program { static void Main(string[] args) { //首先创建一个car对象 Car mycar = new Car("xiaowang",10); //现在告诉汽车他想要向我们发送信息是应该调用哪个方法 mycar.RegisterWithCarEngine(new Car.CarEngineHandler(OnCarEngineEvent)); //方法组转换语句---传递与委托类型一致的函数 //mycar.RegisterWithCarEngine(CallMeHere); //加速,触发事件 Console.WriteLine("*******speed up********"); for(int i=0;i<6;i++) { mycar.Accelerate(20); Console.ReadKey(); } //要传入事件的方法 } public static void OnCarEngineEvent(string msg) { Console.WriteLine("feedback information:{0}", msg); } static void CallMeHere(string msg) { Console.WriteLine("feedback information:{0}", msg); } } }
6.2实现多路广播---见6.1
6.3泛型委托
泛型参数
public delegate void MyDelegate<T>(T mycan);-------对应一类函数
泛型Action<>和Func<>委托------框架内置的委托
泛型Action:可以指向多至16个参数并返回void的方法,需要制定各个参数的具体类型。
Func<>委托:可以指向多至16个参数并且具有自定义返回值。
Func<int,int,int> functarget=new Func<int,int,int>(Add);
Add中本有两个参数,Func<int,int,int>最后一个参数是返回值。
7、事件
event关键字在变已处理的时候,它会自动的提供注册和注销方法以及任何必要的委托类型成员变量,这些成员变量是私有的,不能从出发事件的对象访问。
定义事件:
1)定义委托类型----事件触发时要调用的方法;
2)用相关委托声明这个事件----使用event关键字。
namespace 委托通知 { //使用委托来定义car类,他可以通知外部实体当前引擎状态 /// <summary> /// (1)定义将通知发送给调用者的委托类型 /// (2)声明car类中每个委托类型的成员变量 /// (3)在car上创建副主函数使得调用者能指定由委托成员变量保存的方法 /// (4)修改Accelerate()方法以在适当的情形下调用委托的调用列表 /// </summary> namespace 委托通知 { //使用委托来定义car类,他可以通知外部实体当前引擎状态 /// <summary> /// (1)定义将通知发送给调用者的委托类型 /// (2)声明car类中每个委托类型的成员变量 /// (3)在car上创建副主函数使得调用者能指定由委托成员变量保存的方法 /// (4)修改Accelerate()方法以在适当的情形下调用委托的调用列表 /// </summary> public class Car { //内部状态数据 public int CurentSpeed; public int MaxSpeed; public string name; //汽车能不能用 private bool carIsdead; //类构造函数 public Car() { } public Car(string name, int currentspeed, int maxspeed = 100) { this.name = name; this.CurentSpeed = currentspeed; this.MaxSpeed = maxspeed; } //定义委托类型 public delegate void CarEngineHandler(string msdForCar); //定义每个委托类型的成员变量 private CarEngineHandler listOfhandlers; //向调用者添加注册函数 public void RegisterWithCarEngine(CarEngineHandler methodTocall) { if (listOfhandlers == null) listOfhandlers = methodTocall; else listOfhandlers += methodTocall;//支持多路广播 } //实现Accelerate()方法 public void Accelerate(int delta) { if (carIsdead) { if (listOfhandlers != null) { listOfhandlers("sorry,this car is dead"); } } else { CurentSpeed += delta; //不能超过最大速度 if (5 == (MaxSpeed - CurentSpeed) && listOfhandlers != null) { listOfhandlers("this speed is nearly to the maxspeed"); } if (CurentSpeed > MaxSpeed) { carIsdead = true; } else Console.WriteLine("current speed:{0}", CurentSpeed); } } } public class newCar { //内部状态数据 public int CurentSpeed; public int MaxSpeed; public string name; //汽车能不能用 private bool carIsdead; //类构造函数 public newCar() { } public newCar(string name, int currentspeed, int maxspeed = 100) { this.name = name; this.CurentSpeed = currentspeed; this.MaxSpeed = maxspeed; } //定义委托用来与car的时间协作 public delegate void CarEngineNewHandles(string msg); //汽车可以发送的事件 public event CarEngineNewHandles Exploded; public event CarEngineNewHandles AbouttoBlow; public void NewAccelerate(int delta) { if (carIsdead) { if (Exploded != null) { Exploded("sorry,this car is dead"); } } else { CurentSpeed += delta; //不能超过最大速度 if (5 == (MaxSpeed - CurentSpeed) && AbouttoBlow != null) { AbouttoBlow("this speed is nearly to the maxspeed"); } if (CurentSpeed > MaxSpeed) { carIsdead = true; } else Console.WriteLine("current speed:{0}", CurentSpeed); } } } class Program { static void Main(string[] args) { //////////////////////////////////////////////////////////////////////////使用委托回调 //首先创建一个car对象 Car mycar = new Car("xiaowang", 10); //现在告诉汽车他想要向我们发送信息是应该调用哪个方法 mycar.RegisterWithCarEngine(new Car.CarEngineHandler(OnCarEngineEvent)); //方法组转换的---传递与委托类型一致的函数 //mycar.RegisterWithCarEngine(CallMeHere); //加速,触发事件 Console.WriteLine("*******speed up********"); for (int i = 0; i < 6; i++) { mycar.Accelerate(20); Console.ReadKey(); } ////////////////////////////////////////////////////////////////////////// 使用事件回调 //调用者监听传入的事件 ///先要使用+=h和-=注册和删除事件 newCar c1 = new newCar("wangming", 30); //注册事件处理程序 c1.AbouttoBlow += new newCar.CarEngineNewHandles(CarIsAboutToBlow); c1.AbouttoBlow += new newCar.CarEngineNewHandles(CarIsAmostAboutToBlow); newCar.CarEngineNewHandles d = new newCar.CarEngineNewHandles(OnCarEngineEvent); c1.Exploded += d; for (int i = 0; i < 6; i++) { c1.NewAccelerate(30); Console.ReadLine(); } ///使用方法组转换简化 newCar c2 = new newCar("wangming", 30); //注册事件处理程序 c2.AbouttoBlow += CarIsAboutToBlow; c2.AbouttoBlow += CarIsAmostAboutToBlow; newCar.CarEngineNewHandles d2 = new newCar.CarEngineNewHandles(OnCarEngineEvent); c2.Exploded += d2; } public static void OnCarEngineEvent(string msg) { Console.WriteLine("feedback information:{0}", msg); } public static void CarIsAboutToBlow(string msg) { Console.WriteLine("car is about to blow"); } public static void CarIsAmostAboutToBlow(string msg) { Console.WriteLine("car is about to blow"); } } } public class newCar { //内部状态数据 public int CurentSpeed; public int MaxSpeed; public string name; //汽车能不能用 private bool carIsdead; //类构造函数 public newCar() { } public newCar(string name, int currentspeed, int maxspeed = 100) { this.name = name; this.CurentSpeed = currentspeed; this.MaxSpeed = maxspeed; } //定义委托用来与car的时间协作 public delegate void CarEngineNewHandles(string msg); //汽车可以发送的事件 public event CarEngineNewHandles Exploded; public event CarEngineNewHandles AbouttoBlow; public void NewAccelerate(int delta) { if (carIsdead) { if (Exploded != null) { Exploded("sorry,this car is dead"); } } else { CurentSpeed += delta; //不能超过最大速度 if (5 == (MaxSpeed - CurentSpeed) && AbouttoBlow != null) { AbouttoBlow("this speed is nearly to the maxspeed"); } if (CurentSpeed > MaxSpeed) { carIsdead = true; } else Console.WriteLine("current speed:{0}", CurentSpeed); } } } class Program { static void Main(string[] args) { //////////////////////////////////////////////////////////////////////////使用委托回调 //首先创建一个car对象 Car mycar = new Car("xiaowang", 10); //现在告诉汽车他想要向我们发送信息是应该调用哪个方法 mycar.RegisterWithCarEngine(new Car.CarEngineHandler(OnCarEngineEvent)); //方法组转换的---传递与委托类型一致的函数 //mycar.RegisterWithCarEngine(CallMeHere); //加速,触发事件 Console.WriteLine("*******speed up********"); for (int i = 0; i < 6; i++) { mycar.Accelerate(20); Console.ReadKey(); } ////////////////////////////////////////////////////////////////////////// 使用事件回调 //调用者监听传入的事件 ///先要使用+=h和-=注册和删除事件 newCar c1 = new newCar("wangming", 30); //注册事件处理程序 c1.AbouttoBlow += new newCar.CarEngineNewHandles(CarIsAboutToBlow); c1.AbouttoBlow += new newCar.CarEngineNewHandles(CarIsAmostAboutToBlow); newCar.CarEngineNewHandles d = new newCar.CarEngineNewHandles(OnCarEngineEvent); c1.Exploded += d; for (int i = 0; i < 6; i++) { c1.NewAccelerate(30); Console.ReadLine(); } ///使用方法组转换简化 newCar c2 = new newCar("wangming", 30); //注册事件处理程序 c2.AbouttoBlow += CarIsAboutToBlow; c2.AbouttoBlow += CarIsAmostAboutToBlow; newCar.CarEngineNewHandles d2 = new newCar.CarEngineNewHandles(OnCarEngineEvent); c2.Exploded += d2; } public static void OnCarEngineEvent(string msg) { Console.WriteLine("feedback information:{0}", msg); } public static void CarIsAboutToBlow(string msg) { Console.WriteLine("car is about to blow"); } public static void CarIsAmostAboutToBlow(string msg) { Console.WriteLine("car is about to blow"); } } }
从上面的例子也可以看出,手工定义一个委托对象调用的方法显的有点繁琐,不会很受欢迎,可以在实践注册时之间将一个委托与一段代码相关联-----------匿名方法。
示例代码入下:
//注册事件处理程序作为匿名方法 c3.AbouttoBlow += delegate (string msg) { Console.WriteLine("匿名委托返回消息{0}", msg); Console.ReadKey(); }; c3.Exploded += delegate (string msg) { Console.WriteLine("feedback information:{0}", msg); Console.ReadLine(); }; for (int i = 0; i < 6; i++) { c3.NewAccelerate(5); }
8、Lambda表达式
lambda表达式本质上是用更简单的方法写匿名方法,首先定义一个参数列表,"=>"标记紧随其后,然后就是处理这些参数的语句。
ArgumentsToProcess=>StatementsToProcessThem;参数类型可以是显式的也可以是隐式的。
namespace Lambda表达式 { class Program { static void Main(string[] args) { TraditionalDelegateSyntax(); } static void TraditionalDelegateSyntax() { //创建整数列表 List<int> list = new List<int>(); list.AddRange(new int[] { 20, 1, 4, 8, 444, 8 }); ////使用传统委托方法调用FindAll() //Predicate<int> callback = new Predicate<int>(IsEvenNumber); //List<int> evennumbers = list.FindAll(callback); //foreach (int evennum in evennumbers) //{ // Console.WriteLine("{0} ", evennum); //} //Console.ReadKey(); ////////////////////////////////////////////////////////////////////////// //采用匿名方法 //List<int> evennumbers = list.FindAll(delegate (int num) //{ // return (num % 2 == 0); //}); //foreach (int evennum in evennumbers) //{ // Console.WriteLine("{0} ", evennum); //} ////////////////////////////////////////////////////////////////////////// //采用Lamada表达式 List<int> evennumbers = list.FindAll(num=>(num%2)==0); //运行时被编译成了上述匿名方法 foreach (int evennum in evennumbers) { Console.WriteLine("{0} ", evennum); } Console.ReadKey(); } static bool IsEvenNumber(int num) { //这是个偶数 return (num % 2 == 0); } } }
9、接口
接口是一组抽象成员的命名集合,由接口定义的某个特定成员依赖于它所模拟的确切行为。.NET基础库中提供了几百个预定义的接口类型,由各种类和结构实现。 与抽象类不同,接口只能包含抽象成员,由于C#中类不支持多重继承,一个父类定义的抽象成员只能被其派生类继承,但是大型系统中开发除了Object之外没有公共父类的多个层次结构很普遍,这样就不能配置多层次结构支持相同的多态接口,接口类型解决了这一问题,它可以被任何层次结构。任何命名空间或任何程序集中的任何类或结构来实现,这样接口就有了较高的多态性。
1)不能向类和结构一样分配类型:
Ipointy p=new Ipointy()
2)实现接口是个要"要么全要要么全部不要”的命题,即支持类型无法选择实现哪些成员。
interface IPoint { //接口定义 //1)不指定访问修饰符(默认隐式共有、抽象) //2)不能实现 // byte GetNumofPoint(); //只读属性 byte Points{ get; } } //实现接口时要么全要,要么全不要 class Triangle:Object,IPoint { //... public byte Points { get { return 3; } } } class Program { static void Main(string[] args) { //在对象级别调用接口成员 Triangle triangle = new Triangle(); Console.WriteLine(triangle.Points); Console.ReadKey(); } }
9.1怎样判定一个类型是否支持一个指定接口
1)使用显式强制转换。
static void Main(string[] args) { //在对象级别调用接口成员 Triangle triangle = new Triangle(); try { IPoint point = null; point = (IPoint)triangle; Console.WriteLine(triangle.Points); Console.ReadKey(); } catch (InvalidCastException e) { Console.WriteLine(e.Message); } }
2)as关键字
IPoint point = null; point = triangle as IPoint;
3)is关键字
//在对象级别调用接口成员 Triangle triangle = new Triangle(); try { if (triangle is IPoint) { Console.WriteLine(triangle.Points); Console.ReadKey(); } } catch (InvalidCastException e) { Console.WriteLine(e.Message); }
9.2接口作为参数
interface IPoint { //接口定义 //1)不指定访问修饰符(默认隐式共有、抽象) //2)不能实现 string GetNumofName(); //只读属性 //byte Points{ get; } } //实现接口时要么全要,要么全不要 class Triangle : Object, IPoint { //... public string GetNumofName() { return "i am Triangle "; } } class Rect : Object, IPoint { //... public string GetNumofName() { return "i am Rect"; } } class Program { static public string sayname(IPoint p) { return p.GetNumofName(); } static void Main(string[] args) { //在对象级别调用接口成员 //Triangle triangle = new Triangle(); //try //{ // if (triangle is IPoint) // { // Console.WriteLine(triangle.Points); // Console.ReadKey(); // } //} //catch (InvalidCastException e) //{ // Console.WriteLine(e.Message); //} object[] obj = { new Triangle(), new Rect() }; for (int i = 0; i < obj.Length; i++) { if (obj[i] is IPoint) { IPoint p = (IPoint)obj[i]; Console.WriteLine(sayname(p)); } } Console.ReadKey(); } }
类似的通过as/is关键字的使用,接口也可以作为返回值。
9.3接口数组
接口数组可以包含实现了该接口的任何类或者结构,不论相关不相关。
IPoint[]={new triangle(),new Tree(),new Rect()}
9.4接口的层次结构
1)接口可以继承,继承后如果一个类实现了该接口,则该接口继承的接口成员也需要被实现,同时接口也支持多种继承,若不同接口存在命名冲突,可以通过显式接口解决冲突。