什么是程序集?
---程序集是.net中的概念。
---.net中的dll与exe文件都是程序集。(exe与dll的区别?)
---程序集(Assembly)。可以看做是一堆相关类打一个包,相当于Java中的jar包(*)。
使用程序集的好处?
--程序中只引用必须的程序集,减少程序的尺寸。
---程序集可以疯转一些代码,只提供必要的访问接口。
如何添加程序集的引用?
---添加路径、项目引用、GAC(全局程序集缓存)
---不能循环添加引用
(我们调用的类都是位于各个程序集中,如果调用的类没在引用的程序集中,则需要添加对那个程序集的引用。比如ConfigurationManager。)
访问修饰符、访问级别约束
访问修饰符
private、protected、public
internal(当前程序集)类如果不标注访问级别则是internal级别,也就是只能在程序集内部访问 访问级别约束
子类的访问级别不能比父类的高。(会暴露父类的成员)
类中属性或字段的访问级别不能比所对应的类型访问级别高。
方法的访问级别不能比方法的参数和返回值的访问级别高。
//第一种情况,子类的可访问级别比父类的高 //class Person //{ //} //public class Student : Person //{ //} ////第二种情况,类的访问修饰符和类方法的访问修饰符都高于【参数】的访问修饰符 //class Person //{ //} //public class Test //{ // public void Show(Person p) // { // Console.WriteLine(p.ToString()); // } //} ////第三种情况,类的访问修饰符和类属性或字段的访问修饰符都高于【参数】的访问修饰符 //class Person //{ //} //public class Test //{ // public Person p; // public void Show() // { // Console.WriteLine(p.ToString()); // } //} ////第四种情况,类的访问修饰符和类方法的访问修饰符都高于【参数】的访问修饰符 //class Person //{ //} //public class Test //{ // public Person Show() // { // return null; // } //}
IEnumerable接口
1.通过反编译查看Array、List<T>、ArrayList、Hashtable、Dictionary<K,V>、Queue、Queue<T>、Stack、Stack<T>、c等集合都实现了该接口。
2.IEnumerable接口是干什么的?为什么众多的集合都实现了该接口?
实现这个接口的类型都可以遍历。(数组、集合等都实现了该接口)
实现了该接口的对象都可以放在foreach中循环遍历。
3.IEnumerable<T>泛型版本(学了怎么写泛型类就好理解了)
int[] n = new int[3] { 1, 2, 3 }; IEnumerator ie = n.GetEnumerator(); while (ie.MoveNext()) { Console.WriteLine(ie.Current); } Console.ReadKey();
委托1-什么是委托?
委托是一种数据类型(引用类型),像我们见过的“类”类型一样,只不过“类”类型的变量指向的是一个“对象”,而“委托”类型的变量指向的是一个具体的“方法”。(对方法的包装)
类的使用
1.定义类:class Person{public int Age=10;}
2.实例化类对象: Person p=new Person();
3.使用类对象:p.Age;
委托的使用:
1.委托定义:delegate void SayHiDelegate(string s);
2.实例化委托变量:SayHiDelegate Say=Hello;
3.SayHiDelegate Say=new SayHiDelegate(Hello);
4.Say("大家好”);
public void Hello(string msg)//Hello方法代码
{
Console.WriteLine(msg);
}
问题:这不是和直接调用方法一样吗?还要委托干嘛?
为什么要用委托?
案例1:【演示案例3,把委托作为字段】//自己编写一个项目生成dll文件,然后别人引用你的项目,调用其中Add()、Times()方法,在Add()、Times()方法中都调用了Method()方法。//问题,如何不修改你的项目,并且别人调用ADd与Time时,Method()方法的执行内容不一样。
案例2:有一个方法ChangeString(string[] strArr);传入一个字符串数组,在每个元素两边加一个‘=‘.//当我想让元素全部大写,怎么办?(也可以把委托作为‘参数’)。//将用户的代码“注入”到了你的程序中。
总结:
1.委托像"占位符"一样,预留了一个”空间“,将来调用者决定”到底这里应该执行什么!“,避免了修改已写好的程序。
2.程序需要扩展,但写好的代码不需要修改。避免了类之间的紧耦合。”委托“也是为了让我们的程序”更强大“、”更灵活“,有更好的扩展性。
参考资料《C#图解教程》第15章。
6*2->i*2,i就是在扣窟窿
有一些对字符串数组进行逐个处理的函数,转换为大写、
小写、加引号,如果可以写逐个处理这个数组的多个函数;可以写很多个大写、小写、加引号的小函数,组合出一些函数出来,但是这样的函数仍然是约定死了要调用那些函数的,我想把要调用的函数定义为一个变化的参数,把要它逐个处理的函数定义为一个参数,我传递哪个参数,它就调用哪个参数该多好呀!所以就有了委托。 期望/myfor(e=e.ToUpper()) //期望myfor设定了一个窟窿,开发人员只要填窟窿就可以了!
委托的使用
定义委托类型:delegate 返回值类型 委托名类型名(参数列表)
示例:delegate void SayHelloDelegate(string s);
声明委托类型变量:
SayHelloDelegate say=new SayHelloDelegate(SayHello);//注意:这里只能写方法名,不能加().
--或者SayHelloDelegate say=SayHello;//注意:这里只能写方法名。(这里编译器帮我们new,‘委托推断‘)
SayHello是一个具体的方法,如下:
public void SayHello(string msg){Console.WriteLine(msg);}
注意:这里的say委托可以向普通函数一样调用say("hello").和直接调函数的区别:委托可以理解为”函数指针“,但是它不同于c语言中的”函数指针“,”委托“是类型安全的,它代表了某种类型的方法。
(类型安全:在编译时,已经确定了数据的类型。保证了执行不会出问题)。
小写、加引号,如果可以写逐个处理这个数组的多个函数;可以写很多个大写、小写、加引号的小函数,组合出一些函数出来,但是这样的函数仍然是约定死了要调用那些函数的,我想把要调用的函数定义为一个变化的参数,把要它逐个处理的函数定义为一个参数,我传递哪个参数,它就调用哪个参数该多好呀!所以就有了委托。 期望/myfor(e=e.ToUpper()) //期望myfor设定了一个窟窿,开发人员只要填窟窿就可以了!
小写、加引号,如果可以写逐个处理这个数组的多个函数;可以写很多个大写、小写、加引号的小函数,组合出一些函数出来,但是这样的函数仍然是约定死了要调用那些函数的,我想把要调用的函数定义为一个变化的参数,把要它逐个处理的函数定义为一个参数,我传递哪个参数,它就调用哪个参数该多好呀!所以就有了委托。 期望/myfor(e=e.ToUpper()) //期望myfor设定了一个窟窿,开发人员只要填窟窿就可以了!
委托使用案例1:数据验证控件
编写UserControl。UserControl内有一个textbox,需要对textbox中的值进行验证。将验证时机、验证报错等写在UserControl中,把数据的不同的校验逻辑通过delegate动态指定。 参考代码:
public Validate Validator; private void textBox1_Validating(object sender, CancelEventArgs e) { if (Validator(textBox1.Text) == false) { MessageBox.Show("数据非法"); } } public delegate bool Validate(string txt); //用户只需设置不同的Validator即可。
修改校验的报错方式。userControl是别人写的控件,使用者不用关心什么时候校验,校验出错的时候怎么报错,只要关心对数据进行校验就可以了,使用控件的人不用懂WinForm控件的开发。 控件使用者:不用关心控件在什么时候进行数据校验、校验出错怎么报错,只要指定校验算法就可以。控件开发者:不用把校验算法写死在控件里。
委托使用案例2
案例3:(建两个项目来演示)也可把委托作为参数。
案例4:MySort.DoSort(),实现对int,string,Person类型的排序。提示:string按字符串长度排序,Person按Age排序。
练习1:实现案例5的Person按Age排序。
面向对象编程,遵循“低耦合、高内聚”的编程原则。
“低耦合”:降低不同模块之间的的关联程度,避免修改一个模块影响其他。
“高内聚”:加强同一个模块之间的内容聚合度,同一个模块中的代码相关性很强,“单一职责原则”。
关于案例6,:可以采用冒泡排序法。尽量掌握,面试的时候如果考到排序,如果连最简单的冒泡排序都写不出来就不太好。在.net framework类库中,List<T>的sort()方法也是可以接受一个比较器的。如果每次都重新编写一种排序方法的话,虽然不难,也能实现但是违反了DRY(Don’t Repeat Yourself)原则(不要写重复代码)。
委托使用案例3(作业)
练习4:求给定数组中的最大值
int[] values = { 30,90,7,88,3}; int max = values[0]; foreach (int i in values) { if (i > max) { max = i; } } Console.WriteLine(max); “aa”,”aaaa”,”aaaaaaa” “aaaaaaa” Object[] Object[] n={1,2,4}; Object[] str={“a”,”aa”,”aaa”};
//以上代码是选出最大整数的代码。这段代码只能对int数组取最大整数,如果要实现”字符串数组最长的字符串“、”Person数组取最大的年龄”则每次都要重复写代码。
委托的组合(多播委托、委托连)
delegate void SayHelloDelegate(string s);
多播委托绑定方法的几种方式:
--SayHelloDelegate say=new SayHelloDelegate(SayHello)+new SayHelloDelegate(SayHi);//使用+把两个委托相加时,只能是"委托“相加,不能直接把”方法名“相加。
---快捷方式(增加方法)
-say=SayHello;
say+=SayHI;//不能say=say+SayHi;(两个方法名无法相加)
--快捷方式(取消方法,将此方法从委托中移除)
say-=SayHi;
say-=SayHello;//减的时候注意:加的哪个对象,减的哪个对象,否则”减“不掉。
多播委托中的一些问题
返回值不为void时,如何处理返回值?
委托绑定多个方法后,其中一个方法执行发生异常后面的方法还会继续执行吗?不会!
一个重要的方法GetInvocationList();//返回一个Delegate[]类型。Delegate类是一个抽象类,是所有委托的父类。
委托的本质1(*)
其实就是一个类把方法包装了一下,委托都继承自System.MulticastDelegate,而System.MulticastDelegate又继承自System.Delegate
多播委托就是有一个委托数组,依次调用。
查看自己写的委托的IL代码:
委托的本质2(*帮助理解多播委托)
委托类( System.MulticastDelegate )的3个重要成员
_methodPtr、_target来自Delegate类。
_invocationList来自MulticastDelegate类。//实际上是一个Delegate[]类型
事件1
“事件”的本质其实就是一个对象(一个委托类型的变量),委托是一种类型。 “事件”只是对“委托变量”的包装,其本质依然是委托。
实现事件的基础是“委托”,没有“委托”就没有“事件”。
案例:用委托实现一个“三连击按钮”。//注意在调用委托前,判断委托对象是否为null。(为什么要判断为null?)
直接用委托会有一些问题:
用户可以把之前注册的方法全部覆盖掉
用户可以随意的调用委托 有些时候不想让用户随意覆盖之前注册的方法,不想让用户随意调用委托。怎么办?
事件: 使用event关键字,简化了使用委托时的语法而已。最终编译器生成的代码其实就是委托。
声明事件:event 委托名 事件名
示例:event SayHelloDelegate say;
事件语法:event ProcessWordDelegate{add{...},remove{...}}
add、remove和属性、索引一样最终都编译成两个方法。
如果是简单的增加委托,没有特殊的判断逻辑可以简写,一般情况下都是简写。
加了event关键字实现事件机制的好处:用了event事件,不可以修改事件已经注册的值;不可以冒充进行事件通知了。在IntUC类外部就不能通过OnInt(3)的方式调用注册的委托了。只能+=、-=!
课上练习:实现连续点击三次触发TriClick事件的按钮(用UserControl),用EventHandler这个委托就行。注意不要把判断次数的代码写到用控件的窗口上,否则就违反了封装的原则。 动态设置控件事件
exe与dll的区别?
EXE是可以单独运行的程序。
DLL是不能单独运行,一般是由EXE程序来调用DLL的函数。
DLL一般是封装了一些共享的例程和资源,它通常是一个可以被其它应用程序调用的程序模块。一般扩展名为dll。
它与EXE有些类似,但动态链接库不能被直接执行,只能被其它EXE或者动态链接库调用。
在.NET中,可以通过创建类库的方式创建动态链接库。