.Net培训个人总结笔记15

学习交流,欢迎转载。转载请注明文章来源:http://www.cnblogs.com/lgjspace/archive/2011/10/12/2214010.html

 
细节:
ICollection 接口也是继承自 IEnumerable 接口的,因此 IEnumerable 在多态的使用上能表示的范围更大。

 

技巧:
在 Dictionary<K, V> 中,如果 Key 的值不是有规律的数值类型(例如 Key 为字符串类型值)时,可以通过“foreach(string key in Dict.Keys)”的方式来进行逐个遍历,然后通过被遍历出的每个Key来查找出 Dict 中 Key 对应的 Value ,从而实现对键值对的遍历功能。

 

细节:
之所以 Dictionary 运行速度这么高就是因为在 Dictionary 内部使用了类似于“目录”的机制:以存储 Key 为“国”、Value 为“帼”的键值对为例,当程序要找 Key 为“国”的 Value 时,在 Dictionary 内部不会像普通的检索那样对每个元素进行遍历,它有一种算法,可以对Key进行计算,得出的就是存放 Value 的地址,这样下来,检索时就不用对 Key 和 Value 遍历,而是像“查字典的目录”一样,来直接“查”出 Key 对应的 Value。Dictionary 内部实现原理(即“根据 Key 来找 Value 的房间号”的原理)涉及到数据结构中的“散列表”和“哈希表”的知识。

 

细节:
HashSet<T> 不能盛放重复的数据,若放了重复的数据时不会报错,但会只保留一份。
HashSet<T> 使用了和 Dictionary 类似的算法,因此 Contains 方法的效率也是非常高的。
ArrayList 和 List<T> 也和 HashSet<T> 一样也有 Contains 方法,但这两个类的 Contains 方法和 HashSet 中的 Contains 方法从效率上来说是完全不一样的,前两者是属于“逐个遍历”,而 HashSet<T> 则属于“目录式的检索”。

 

概念:
时间复杂度和空间复杂度:通俗地讲,就是在问题规模为 n 的时候,最坏最悲惨的情况下所需要耗用的时间和空间(内存)的多少,用“大O表示法”来表示:O(1)、O(N)、O(N*N)、O(N的N次方)等,只表示最大数量级,不用记录精确数值。

 

细节:
栈 Stack<T> 和队列 Queue<T> 中,栈是先入后出,而队列则刚好相反,先入先出。在 Stack<T> 中,压栈就是 Push ,出栈就是 Pop;而在 Queue<T> 中,入队就是 Enqueue,出队就是 Dequeue。

 

重点:
1. 函数本质上是通过“传参数”的形式来“隔离了代码段中变量的变量值的变化”,而实现重用代码段的功能;
2. 委托的功能类似于函数,本质上也是“隔离变化”,函数是“通过传参数的形式来隔离变量值的变化”,而委托则是“通过传函数的方式来隔离操作流程或者是操作方式的变化”,相对来说,委托隔离的变化的范围更宽泛,不像函数那样仅局限于隔离变量的值的变化。
3. 在 C# 中的委托就是安全的函数指针。
4. 声明委托变量的语法(注意:这是声明委托类型的语法,而不是声明委托变量的语法):
delegate 将要被调用的函数的返回值类型 该委托的类型名(将要被调用的函数的参数类型以及参数值(可以不止一个参数,具体取决于被调用的函数的参数格式(即函数签名)。));

 

经验:
如下面代码所示:
代码一:

 1 namespace DelegateDemo
2 {
3 class Program
4 {
5 delegate void MyDelegate(string s);
6 //细节:下面这行这样会报错:“字段初始值无法引用非静态字段、方法或属性。”
7 //MyDelegate md = new MyDelegate(SayHello);
8 static void Main(string[] args)
9 {
10 //不能像下面这行这样写(即不以对象调用的方式,即“对象.方法”的方式来调用非静态类的 SayHello 方法),会报错:“非静态的字段、方法或属性要求对象引用”。
11 //MyDelegate md = new MyDelegate(SayHello);
12 //要像下面这样写:
13 Program p = new Program();
14 MyDelegate md = new MyDelegate(p.SayHello);
15 md("special");
16 md("command");
17 md("Normal");
18 Console.ReadKey();
19 }
20
21 private void SayHello(string name)
22 {
23 Console.WriteLine("Hello " + name + "!");
24 }
25 }
26 }

代码二:

 1 namespace DelegateDemo
2 {
3 class Program
4 {
5 delegate void MyDelegate(string s);
6 MyDelegate md;
7 //如上面一行,要是把委托变量声明在 Main 方法外、Program
8 //类里,md 就成了类的成员字段,因此在 Main 方法中直接调
9 //用该变量会报错“非静态的字段、方法或属性要求对象引用”。
10 static void Main(string[] args)
11 {
12 Program p = new Program();
13 //下面四行都会报错,因为 Main 方法是静态方法,而 md 则是 Program 类的非静态字段,
14 //所以构成了“在静态方法中调用非静态类的成员”,会报错。
15 //md = new MyDelegate(p.SayHello);
16 //md("special");
17 //md("command");
18 //md("Normal");
19 Console.ReadKey();
20 }
21
22 private void SayHello(string name)
23 {
24 Console.WriteLine("Hello " + name + "!");
25 }
26 }
27 }

 

细节:
委托除了可以用“new”的方式来给委托“绑定”将要被调用的函数之外,还可以用“直接 = ”的方式来给委托“绑定”要被调用的函数,但后者实际上是C#的编译器自动为我们的这种写法改成像第一种(用“new”来“绑定”函数)的方式,即相当于自动帮我们“new”了一个。例如:

1 delegate void MyDelegate();
2 MyDelegate md;
3 //假设以下出现的“Method”为可以被委托 md 调用(即方法签名和委托对象 md 的签名一样)的方法。
4 //方式一:
5 md = new MyDelegate(Method);
6 //方式二:
7 md = Method;

注意!!!“md = Method;” 和 “md = Method();” 是完全不一样的,前者是把函数名赋给委托变量,实质上是相当于把委托这“指针”“指向”函数Method;而后者则是先调用“Method()”函数,把该函数的返回值赋给委托变量 md,很显然,这样会报错。

 

细节:
可以供委托变量“绑定”的方法必须要有和该委托变量的类型相同的签名,即将要被调用的方法必须要和该委托类型声明时定下的“函数返回值类型”、“传进函数的参数值的类型”、“传进函数的参数的个数”和“传进函数的参数的顺序”完全一致(但参数的变量名除外,不要求必须相同),否则会报错。

 

区别:

 1 static int CompareCharASCII(object o1, object o2)    //判断所传入的字符转换成 ASCII 码后的值的大小。
2 {
3 byte b1;
4 byte b2;
5 try //这里涉及到了 Cast 方式的转换和 Convert 方式的转换的不同。
6 {
7 //方式一:先把 o1 转换为 char 类型,然后再把已转换成 char 类型的 o1 进一步转换为 byte 类型。
8 //注意!不能把 o1 直接转换成 byte 类型,这样会报错。
9 b1 = (byte)(char)o1;
10
11 //方式二:
12 b2 = Convert.ToByte(o2);
13 }
14 catch (Exception ex)
15 {
16 throw new Exception("数据类型非法!");
17 }
18 return b1 - b2;
19 }

 

细节:
int→object 和 int[]→object[] 两种关系的区别:
int 类型是 object 类型的子类,但 int[] 类型不是 object[] 类型的子类。同样地,这种区别在其他的数组和 object 类型数组之间也同样存在。

 

细节:
1.委托的多个变量可以以“加”的方式来把多个组合;也可以以“减”的方式来把一个由多个委托对象组合起来的委托变量分解开来。注意:组合时是有顺序的。
2.如果委托组合中的每个元素是有返回值的话,委托组合的返回值则是最后被调用的委托元素的返回值。
3.一般来说,只有 Sort、Max 等这样的委托有返回值之外,用来实现事件的时候一般委托都没有返回值。例如:

 1 delegate int MyDelegate(object o1,object o2);
2 MyDelegate md0, md1, md2;
3 //方式一:
4 md0 = new MyDelegate(IntComparer) + new MyDelegate(StringLengthComparer) + new MyDelegate (CharASCIIComparer);
5 //方式二:
6 md0 = new MyDelegate(IntComparer);
7 md1 = new MyDelegate(StringLengthComparer);
8 md2 = new MyDelegate (CharASCIIComparer);
9 md0 = md0 + md1 + md2; //注:这和“md0 = md0 + md2 + md1;”的组合顺序是不一样的。
10 md0 = md0 + md0 + md1 + md1 + md2 + md1; //注:可以重复添加,逐个调用。
11 md0 += md1; //这样也可以组合委托。
12 md0 += IntComparer //也可以直接“添加函数名”来添加委托元素,其实这里内部为 IntComparer 自动地 new了一个委托对象,再赋值给委托变量 md0。
13 md0 -= IntComparer //同样地,也可以直接“减等于”一个函数名。注意:即使委托组合中没有的委托元素也可以用“减等于”,而且不会报错。
14 md0 = md0 - md1; //也可以用“减”来移除。
15 md0 -= md1; //这样也可以移除委托。
16 //下面是三个被上面的委托变量调用的函数的函数头,内容不需要关注,被省略。
17 static int IntComparer(object o1, object o2)
18 {
19 }
20 static int StringLengthComparer(object o1, object o2)
21 {
22 }
23 static int CharASCIIComparer(object o1, object o2)
24 {
25 }

 

重点细节:
在匿名方法中,如果匿名方法需要返回一个值的话,在匿名方法声明时不需要标明返回值,直接在匿名方法的方法体里面 return 回来即可。

 

细节:
C#中的访问级别约束:
1.子类的可访问级别不能比父类高(类似于人类的“等级观念”,“儿子能去的地方爹一定要能去”);
2.参数所属的类型的可访问级别不能比方法本身的可访问性级别低。
3.字段所属的类型的可访问级别不能比字段本身的可访问性级别低。
4.属性所属的类型的可访问级别不能比属性本身的可访问性级别低。例如:

1 public class Person
2 {
3 public Dog dog { get; set; } //这里的属性的可访问级别是 public ,而该属性所用到的类型 Dog 的声明部分(Dog的声明部分在下面)用的是默认的 Internal,比这里用的 public 要低,所以这里会报错:“可访问性不一致:属性类型比属性的可访问性低。”
4 }
5 class Dog //Dog 类型的声明部分,这里不写明可访问级别关键字,即相当于用了类的默认可访问级别“internal”。
6 {
7 //......
8 }

 

细节:
直接用委托来实现的事件的缺陷:
1.在外界可以清除已经被监听的委托。
2.在外界可以伪造事件的触发。
其缺陷的根源都是:对外界来说,监听事件的委托对于外界来说都是 public 的,没有安全性。
相对于这种直接用委托来实现的“伪事件”,真正的事件(以 event 实现的事件)不能在外部调用委托来触发事件,也不能清空委托所监听的事件,在外部可以执行的操作只能是添加或删除监听事件。

 

细节:
 C# 不等于 .Net,event 只是 C# 里面的关键字,不是 .Net 范畴的东西,但它会在编译时被编译器翻译成相应的(内部还是以委托实现的)事件机制。

 

重点:
面试时遇到“委托和事件的关系”(注意不是“区别”是“关系”)的问题时的答法(大概内容):
1.用委托也能实现事件的机制,真正的事件机制内部也是通过委托来实现。
2.event 会自动地帮我们 private 要用来监听事件的委托对象,同时向外部暴露 Add、Remove(即相当于“+=”和“-=”)两个方法,让外界只能“+=”和“-=”。
3.event 会自动生成一个private delegate 变量和两个函数:add 和 remove,C# 编译器用这两个方法支持 += 和 -= 操作符。

posted @ 2011-10-12 23:41  梁国锦  阅读(315)  评论(0编辑  收藏  举报