C#总结(五)
 
十三、委托和事件
1、委托的协变
 class Phone
    {
    }
    class Mobile : Phone
    {
    }
    delegate Phone PhoneDele();//声明委托
    class Program
    {
        static void Main(string[] args)
        {
            Program pro = new Program();
            PhoneDele pd1 = pro.GetPhone;//将委托与方法建立联系
            PhoneDele pd2 = pro.GetMobile;//委托类型的协变------------将(返回值 子类对象赋给父类对象)
        }
        public Phone GetPhone()
        {
            return null;
        }
        public Mobile GetMobile()
        {
            return null;
        }
    }
委托的逆变
 class Phone
    {    }
    class Mobile : Phone
    {    }
    delegate void PhoneDele(Mobile  pho);
    class Program
    {
        static void Main(string[] args)
        {
            Program pro = new Program();
            PhoneDele pd1 = pro.SetPhone;//委托类型的逆变-----传参和返回值的路径和方向正好是反着的 所以仍然是子类对象赋给父类对象
            PhoneDele pd2 = pro.SetMobile;
        }
        public void SetPhone(Phone pho)
        {     }
        public void SetMobile(Mobile mob)
        {  }
    }
2 事件
事件是依附于委托的,委托是和方法联系的。当触发事件时,会调用相应的方法处理事件
1)类或对象可以通过事件向其他类或对象通知发生的相关事情。发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”。
事件具有以下特点:
       发行者确定何时引发事件,订户确定执行何种操作来响应该事件。
     一个事件可以有多个订户。一个订户可处理来自多个发行者的多个事件。
       没有订户的事件永远不会被调用。
      事件通常用于通知用户操作,例如,图形用户界面中的按钮单击或菜单选择操作。
       如果一个事件有多个订户,当引发该事件时,会同步调用多个事件处理程序。
       可以利用事件同步线程。
       在 .NET Framework 类库中,事件是基于 EventHandler 委托和 EventArgs 基类的。
2)//定义委托
delegate void MyDele(string str);
    class Program
    {    //定义事件
        event MyDele MyEvent;
        static void Main(string[] args)
        {
            Program pro = new Program();
            //订阅方法
            pro.MyEvent += new MyDele(pro.MyMethod);
            pro.MyMethod("参数1");
        }
        //定义委托方法
        public void MyMethod(string str)
        {
            Console.WriteLine("方法参数为:" + str);
        }
    }
2)事件定义之后,只能在本类中调用,其他的地方只能是“+=”
十四、静态类 密封类 抽象类
1)sealed class MySeaClass
    {
     
    }
不能做基类,它也不能是抽象类,它主要是用于防止派生
2)静态类
静态类和类成员用于创建无需创建类的实例就能够访问的数据和函数。静态类成员可用于分离独立于任何对象标识的数据和行为:无论对象发生什么更改,这些数据和函数都不会随之变化。当类中没有依赖对象标识的数据或行为时,就可以使用静态类
3)不能使用new关键字创建静态类的实例,静态类在加载包含该类的程序或命名空间时由 .NET Framework 公共语言运行库 (CLR) 自动加载。
4)用静态类来包含不与特定对象关联的方法
仅包含静态成员
不能被实例化
是密封的
不能包含实例化构造函数
5)静态方法和属性属于类的,静态方法和属性只能访问静态字段和静态事件,静态成员不随对象的状态变化
静态方法可以被重载,但不可以被重写
6)抽象类是接口和实例化类的中和,内部可以是抽象成员也可是实例成员
使用 abstract 关键字可以创建仅用于继承用途的类和类成员,即定义派生的非抽象类的功能。
public abstract class A
 {
// Class members here.
}
 
抽象类不能实例化。抽象类的用途是提供多个派生类可共享的基类的公共定义
抽象类也可以定义抽象方法。方法是将关键字 abstract 添加到方法的返回类型的前面。
7) 接口
接口是使用 interface 关键字定义的。
interface IMyInterface
{
}
接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。
不能直接实例化接口。
接口可以包含事件、索引器、方法和属性。
接口不包含方法的实现。
类和结构可从多个接口继承。
接口自身可从多个接口继承。
继承新类(即派生类)将获取基类的所有非私有数据和行为以及新类为自己定义的所有其他数据或行为。因此,新类具有两个有效类型:新类的类型和它继承的类的类型。
 
以下是补充:
1)结构是可以赋值为null的,这与其它的值类型不太一样,如果值类型想赋值为null的话,则要加?号才行。
2)结构和类之间的区别。
A  在结构中,如果重载构造函数,系统默认的无参的构造函数也是存在的,而类中这个默认的构造函数是会被新的构造函数所代替的。B  在结构中,一旦有构造函数,那么,所有在结构中声明的字段(除了常量和静态的),都是需要在构造函数中赋值的(成员是不能自己给自己赋初值的,只能在构造函数中),而类中是根据需要来赋值。
C  结构中,如果实例化时,是可以不用new关键字的,如果用new关键字来调用的话,系统会默认的赋初值的,若不用,则必须先给其赋值,然后使用;而类中只能通过new来调用。
3)集合
常用的有Arraylist和List:
A    Arraylist,来自命名空间System.Collections;它通过Add()方法来添加数据,可以用名称[0]来取或修改已有元素的值
B   如果在这指定长度,则这个长度指的是容量,并不是集合里面数据的长度(该长度一般用Count来取),它的默认长度是4,超过后就要翻倍:4,8,16。。。
C   泛型list的用法和Arraylist差不多,但是泛型用起来要比Arraylist要好用,推荐使用泛型。
4)  类
类中的成员可以有字段、方法、属性、索引器、事件、委托
5)        Ref和 out的操作对象都是值类型的数据。它们可以将值类型的数据临时的当引用类型的来用。
Ref 是将这个变量的名称和数据(地址)都带进去,出来时全带出来
out只能将这个变量的名称带进去,之后,在方法中要先对其赋值,然后进行相应的操
Params是一个动态的参数。范围(0到n)
如果在定义时并不知道要传进去的参数的个数,可以通过定义Params这个动态的参数。
6)分部方法不能有访问修饰符的
扩展方法,就是针对一些系统类和一些不能实现继承的类(如密封类),我们需要来添加一些方法供我们使用,但是,由于是系统自定义的,我们肯定是看不到源代码的,不能直接对其修改,这样,扩展方法就出场了。
定义:扩展方法必须在静态类中定义,扩展的方法也必须是静态的,方法中的参数用this关键字加上要扩展的类名  。
7) 委托
是一种承载方法的,这个方法可以有多个。方法有实例方法,静态方法,回调方法(异步),我们可以把委托想象为父类,而承载的方法是子类,也就是说,子类通过重载实现了父类的方法。这样,我们就知道,方法不必与委托签名完全匹配的---------委托的协变和逆变。
委托是和类一个级别的,因此,委托可以定义到类的外面,亦可以在类的里面。
使用委托的步骤:
1、  定义委托
2、  定义方法
New委托,将方法赋给委托(在这里,new有两个功能,一个是分配内存空间,二是完成指针的功能。给委托建立联系时,方法名一定不能加括号(如果有括号,就成了调用了)。
3、  
委托的协变和逆变:它们的本质都是子类型赋给父类型。不同的是,协变的赋值对象是返回值,而逆变的赋值对象是参数(参数的传递方向和返回值的正好相反)
8)
抽象类时不能实例化的,其成员是不能有抽象字段的,抽象的方法和字段都不能赋值。
抽象类中可以没有抽象成员
抽象类是可以被继承的,一旦定义了抽象的方法、属性、索引器、事件,那么子类要是想重新覆盖,必须使用关键字override。
实例化继承的抽象类时,要将抽象类中所有的抽象成员实例化
抽象类继承抽象类时,可以不实例化其抽象成员。
如果构造函数有参数的话,必须继承
抽象类也可以继承实例化类
9)接口
用interface关键字来声明。接口与抽象类不同的是:
任何非抽象类,如果继承了该接口,那么子类都必须实现接口的所有成员
接口中的成员都只能声明,不能够实现的(抽象类中的抽象方法是可以实现的)
接口中的成员一共有四种:方法、属性、事件、索引器。
接口中成员的访问修饰符只能是public,而且,在声明的时候,是不允许写出public的,系统会默认的添加
接口是支持多重继承的,也就是说,类和接口可以从多个接口继承,
10)
继承:类可以从其他类中继承,这样,子类就拥有了父类的一些方法和属性等;
如果子类想覆盖父类的方法,则必须在父类的方法中用virtual关键字声明,然后在子类中用override关键字来覆盖;
如果子类要定义一个与父类具有相同的方法签名的方法,那么,可以使用new关键字显式的隐藏父类的方法(如果没有new的话,会隐式的隐藏)