zoukankan      html  css  js  c++  java
  • .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# 编译器用这两个方法支持 += 和 -= 操作符。

  • 相关阅读:
    本地文件上传到Linux服务器
    进阶线路
    process.env.NODE_ENV
    Docker 实践备忘录
    Sae配置Java数据库连接
    Java实现微信菜单json字符串拼接
    spring+hibernate+jpa+Druid的配置文件,spring整合Druid
    根据当前节点获取所有上层结构的组织(递归算法)
    实现左右两边用户添加、删除、调位置(上下移动)、排序等的功能
    Dom4j解析Xml文件,Dom4j创建Xml文件
  • 原文地址:https://www.cnblogs.com/lgjspace/p/2214010.html
Copyright © 2011-2022 走看看