C#复习笔记(2)--C#1所搭建的核心基础
通过对C#1所搭建的核心基础的深入了解,可以知道之后的C#版本在C#1的基础上做了很多扩展,而这些扩展都是基于C#搭建的核心基础而来的。
委托
一、编写委托的过程
委托经常和C语言的“函数指针”挂钩。委托是方法参数化、函数式语言一个重要的表达方式。C#1中编写一个委托要经过四部:
1、声明委托类型
delegate void StringProcessor(string param1);
这个委托指定了一种无返回值,有一个string类型的参数的方法。
这个委托继承自System.MulticastDelegate,后者又派生自System.Delegate.
委托本身是引用类型,所以声明委托的时候不能在方法中声明。可以作为内部类,也可以声明到namaspace下面。
2.、必须有一个方法包含了要执行的代码,这个方法要和委托声明的签名一致,包括参数和返回值
C#一中要为委托找到一个方法的话必须要和委托的签名完全一直,在C#2中允许委托的斜边和逆变。必须下面的委托:
delegate object SayHello(string word);
这个委托可以被下面这个方法实例化:
static string Sayhello(object word)
{
Console.WriteLine(word);
return word.ToString();
}
3、创建委托本身
可以采用new操作符来创建一个委托的实例:
SayHello say = new SayHello(Sayhello);
C#2中支持委托-方法组的转换,所以,可以直接使用
SayHello say = Sayhello;
4、调用委托
一切准备就绪后就可以用invoke方法来完成调用。C#还可以更简单的完成这个操作,使用
SayHello say = Sayhello;
say("hello,you");
就可以完成,不过在背后编译器帮你完成了一些工作:

二、合并和删除委托
委托和string的特征有一些相似:都是不易变的。这体现在委托的合并和删除上面:
委托内部有一个操作列表(invocation list):System.Delegate的静态方法Combine和Remove负责创建新的委托实例。其中,Combine将两个委托的操作列表链接到一起,Remove负责将一个委托实例的一个操作删除。它们都不改变原有的类型(所以说和string很像)他们都是返回一个Delegate。
很少在代码中直接调用Delegate.Combine,Delegate.Remove而是用+=和-=操作符。这同样是编译器的功劳:

如果调用列表中抛出异常,那么抛出异常的那个方法导致调用列表不在执行。
如果有返回值,那么调用列表会返回最后调用的那个方法的值。所以一般不会在调用列表中执行有返回值的方法。
但是如果有必要,可以通过调用invocationlist来逐个执行方法并获取返回值。
三、事件
首先来看事件的声明:
public event SayHello SayHelloEvent;
事件是对委托的封装,有点儿类似于属性和后备字段的关系,上面这句声明编译器会做如下工作:
1、在相同的作用域中声明一个SayHello委托类型的私有字段
2、声明一个类似于属性的块结构,这个块结构包含一个类似于属性的取值方法和赋值方法,由编译器进行命名,前缀分别是"add"和"remove"。
3、在外部,会通过+=和-=来操作事件,声明事件时的访问修饰符会限制这一操作。就是说如果声明为一个private的事件的话外部是不能操作事件的。
4、在内部,+=操作符会调用“add”前缀的方法,“add”前缀的方法会调用Delegate.Combine来合并操作,同理,-=操作符会调用“remove”前缀的方法,该方法会调用Delegate.Remove来删除操作。
5、从上面可以看出,事件就是一对儿“add"和”remove“方法。他封装了委托,从而避免调用方直接操作委托,而是通过事件来间接的操作委托,在类的内部可以看到委托,在类外部可以看见事件。
总结一下,事件不是委托实例,只是成对儿出现的add/remove方法。类似与属性的get/set方法。
类型系统的特征
在C#4之前,C#的类型系统是静态的、显式的和安全的。
一、静态类型和动态类型
C#是静态类型的:每个变量或表达式的类型在编译时都是已知的。只有类型已知的操作才是被允许的。静态这个词用来表示使用不变的类型数据来分析哪些操作可用。
与静态类型想对应的是动态类型,动态类型的实质是变量中含有值,但那些值不限于特定的类型。所以编译器不能执行相同形式的检查。
二、显示类型和隐式类型
这个讨论只有在静态语言的环境中才是成立的。对于显式类型来说,每个变量都在声明时指定类型。隐式类型则允许编译器变量的用途来确定变量的类型。无论是显式还是隐式,表达式的类型都会在编译时就确定。
三、类型安全与类型不安全
C#是类型安全的,C#支持一些类型安全的转换:继承上的、数值上的,如果使用强制类型转换,编译器会检测转换的结果,也会抛出异常来组织程序的继续运行,C#还支持有限的协变和逆变(C#4)。但是和真正的协变和逆变还有很长一段距离。
可以通过显式实现接口来处理协变和逆变上的一些限制。
总结一下:
C# 1是静态类型的—— 编译器知道你能使用哪些成员;
C# 1是显式的—— 必须告诉编译器变量具有什么类型;
C# 1是安全的——除非存在真实的转换关系, 否则不能将一种类型当做另一种类型;
静态类型仍然不允许一个集合成为强类型的“ 字符串列表” 或者“ 整数列表”, 除非针对不同的元素使用大量的重复代码;
方法覆盖和接口实现不允许协变性/ 逆变性。
值类型和引用类型
一、值类型和引用类型的基础知识
对于引用类型的表达式(如一个变量),它的值是一个引用,而非对象。
引用就像URL——是允许你访问真实信息的一小片数据。
对于值类型的表达式,它的值是实际的数据。
有时,值类型比引用类型更有效, 有时恰好相反。
引用类型的对象总是在堆 上, 值类型的值既可能在栈 上, 也可能在堆上,具体取决于上下文。
引用类型作为方法参数使用时, 参数默认是以“值传递”方式来传递的—— 但值本身是一个引用。
值类型和引用类型的本质区别在于复制的方式不同:值类型复制值本身,引用类型复制的是引用。
两种类型的另一个差异在于, 值类型不可以派生出其他类型。 这将导致的一个结果就是,值不需要额外的信息来描述值实际是什么类型。 把它同引用类型比较, 对于引用类型来说, 每个对象的开头都包含一个数据块, 它标识了对象的实际类型, 同时还提供了其他 一些信息。 永远都不能改变对象的类型——执行简单的强制类型转换时, 运行时会获取一个引用, 检查它引用的对象是不是目标类型的一个有效对象。如果有效, 就返回原始引用; 否则抛出异常。 引用本身并不知道对象的类型—— 所以同一个引用“ 值” 可用于( 引用) 不同类型的多个变量。 例如 下面 的 代码:
Stream stream=new MemoryStream();
MemoryStream memory = (MemoryStream) stream;
//第1行创建一个新的MemoryStream对象, 并将stream变量的值设为对那个新对象的引用。 第2行检查stream的值引用的是不是一个MemoryStream( 或派生类型)对象,并将MemoryStream的值设为相同的值。
值类型变量本身存储的是值,引用类型变量本身存储的是引用,这个引用里面包含一个指向真正对象的地址。
变量的值在它声明时的位置存储。局部变量的值总是存储在栈( stack)中(这个结论只有 在C#1中完全成立。以后会讲到,在更高版本C#中,在特定情况下,局部变量最终可能存储在堆中。)实例变量的值总是存储在实例本身存储的地方。 引用类型实例(对象)总是存储在堆( heap)中, 静态变量也是。
按值传递和按引用传递的区别是按值传递的是副本,按引用传递的是别名。
装箱的背景在于值类型和引用类型的值不同:值类型的值就是值本身,而引用类型的值只是一个引用。
值类型的值会在需要引用类型的行为时被装箱; 拆箱则是相反的过程。
构建于C#1之上的新特性
一、与委托有关的新特性
C#1中的委托-->C#2的泛型、方法组转换、匿名方法、委托协变性和逆变性-->C#3的lambda表达式、内建的Func、Action、泛型的接口和委托的协变性和逆变性
二、与类型系统有关的特性
C#2-->泛型、委托的协变性和逆变性-->C#3匿名类型、隐式类型、扩展方法-->C#4受限的泛型协变性和逆变性、动态类型
三、与值类型有关的特性
C#2-->泛型、Nullable<t>可空值类型
C#复习笔记(2)--C#1所搭建的核心基础的更多相关文章
- c#1所搭建的核心基础之值类型和引用类型
这个主题很重要,在.NET中做的一切其实都是在和一个值类型或者引用类型打交道. 现实世界中的值和引用 假定你在读一份非常棒的东西,希望一个朋友也去读他.于是你到复印室里复印了一份.这个时候他获得了属于 ...
- c#1所搭建的核心基础之类型系统的特征
类型系统的特征简介 几乎每种编程语言都有某种形式的一个类型系统.类型系统大致被分为:强/弱,安全/不安全,静态/动态,显式/隐式等类型. c#在类型系统世界中的位置 c#1的类型系统是静态的.显式的和 ...
- c#1所搭建的核心基础之委托
本文将对c#1的委托进行详细探索 委托(delegate) 注 delegate:vt.委派代表; 授权给; [法律]债务转移; 委托作用:在恰当的时间执行一系列操作 1.简单委托的构成 声明委 ...
- C#1所搭建的核心基础
一,委托 委托封装了包含特殊返回类型和一组参数的行为,类似包含单一方法接口. 委托类型声明中所描述的类型签名决定了哪个方法可以用于创建委托实例,同时决定了调用的签名:委托类型实际上只是参数类型的一个列 ...
- Java基础复习笔记系列 九 网络编程
Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ...
- Java基础复习笔记系列 八 多线程编程
Java基础复习笔记系列之 多线程编程 参考地址: http://blog.csdn.net/xuweilinjijis/article/details/8878649 今天的故事,让我们从上面这个图 ...
- Java基础复习笔记系列 七 IO操作
Java基础复习笔记系列之 IO操作 我们说的出入,都是站在程序的角度来说的.FileInputStream是读入数据.?????? 1.流是什么东西? 这章的理解的关键是:形象思维.一个管道插入了一 ...
- Java基础复习笔记系列 五 常用类
Java基础复习笔记系列之 常用类 1.String类介绍. 首先看类所属的包:java.lang.String类. 再看它的构造方法: 2. String s1 = “hello”: String ...
- Java基础复习笔记系列 四 数组
Java基础复习笔记系列之 数组 1.数组初步介绍? Java中的数组是引用类型,不可以直接分配在栈上.不同于C(在Java中,除了基础数据类型外,所有的类型都是引用类型.) Java中的数组在申明时 ...
随机推荐
- 为什么zookeeper集群中节点配置个数是奇数个?
Zookeeper的大部分操作都是通过选举产生的.比如,标记一个写是否成功是要在超过一半节点发送写请求成功时才认为有效.同样,Zookeeper选择领导者节点也是在超过一半节点同意时才有效.最后,Zo ...
- nuxt拦截IE浏览器
需求场景 判断浏览器类型,让譬如IE的低版本浏览器跳转到指定提示浏览器升级页面. 难点分析 使用过的都知道,nuxt没有暴露主入口页面也就是index.html啊,我们以前常用的IE条件判断没地方写. ...
- vue-router 管理视图详解
什么是路由 在web开发中,路由是指根据url分配到对应的处理程序,当访问不同的url就会切换到对应的处理程序 在vue中一个url对应的就是一个组件,当访问不同的url,对应的组件就会呈现到页面中 ...
- Scrapy 框架 总结
总结: 1.中间件:下载中间件(拦截请求和响应) - process_request: - prceess_response: - process_exception: - 请求: - UA伪装: - ...
- 为什么java的类是单继承的,接口是多继承的
类 如果一个类继承了两个类,但是这两个类中有相同的方法,那么子类调用方法时,无法确定应该调用哪个父类的方法. [c++是多继承的] 接口 jdk1.7 接口可以多继承,是因为当接口中是抽象方法.不存 ...
- Python-wxpy继承关系
聊天对象 通过机器人对象 Bot 的 chats(), friends(),groups(), mps() 方法, 可分别获取到当前机器人的 所有聊天对象.好友.群聊,以及公众号列表. 而获得到的聊天 ...
- 多个窗口开启后,切换到指定title的窗口
1.在google中,可以开启多个窗口,这是需要切换到自己需要的窗口去定位元素.如下: #获取两个窗口的标题 ${titles} Selenium2Library.Get Window Titles ...
- 理解Shadow DOM(一)
1. 什么是Shadow DOM? Shadow DOM 如果按照英文翻译的话可以理解为 影子DOM, 何为影子DOM呢?可以理解为一般情况下使用肉眼看不到的DOM结构,那如果一般情况下看不到的话,那 ...
- BottomNavigationBar
重点: bottomNavigationBar: BottomAppBar( shape: CircularNotchedRectangle(),//这个就是设置floatingactionbutto ...
- Git分支管理规范
关于Git的一些分支管理规范... 一.分支与角色说明 Git 分支类型 master 分支(主分支) 稳定版本 develop 分支(开发分支) 最新版本 release 分支(发布分支) 发布新版 ...