31.比较值类型的相等性
ReferenceEquals()用于比较引用,Equals()用于比较值。比较运算符可以看作一个中间项,但最大的区别是值类型需要装箱才能把它转化为引用。
32.比较运算符重载
语句if(a==b)对于类,这个语句在默认状态下会比较引用a和b,检测这两个引用是否指向内存中的同一个地址,而不是检测两个实例实际上是否包含相同的数据。
C#要求成对的重载运算符,比较运算符必须返回bool类型的值。
33.比较运算符:浅度比较与深度比较
如果有嵌入的类,浅度比较:比较引用是否指向同一个对象 深度比较:比较对象的值是否相等
34.基类和派生类之间的类型强制转换
在进行类型强制转换时,会检查被引用的对象,因为基类引用原则上可以引用一个派生类的实例,如果该对象不是派生类的一个实例,强制转换就会失败。
35.委托
委托是类型安全的类,它定义了返回类型和参数的类型,委托类不仅包含对方法的引用,也可以包含对多个方法的引用。
当参数是委托类型时,就可以使用lambda表达式实现委托引用的方法。
当要把方法传送给其他方法时,需要使用委托。
36.声明委托
使用委托时,首先必须定义要使用的委托,必须创建该委托的一个或多个实例。定义的前面加上关键字delegate,
37.委托推断
为了减少输入量,只要需要委托实例,就可以只传送地址的名称。委托推断可以在需要委托实例的任何地方使用,也可以用于事件,因为事件基于委托。
38.泛型Action
39.多播委托
如果要调用多个方法,就需要多次显式调用这个委托。但是,委托也可以包含多个方法。这种委托称为多播委托。如果调用多播 委托,就可以按顺序连续调用多个方法。为此,委托的签名就必须返回void
40.GetInvocationList()
为了避免因为前面方法抛出异常,导致迭代停止,可以自己迭代方法列表。delegate类定义GetInvocationList()方法,它返回一个Delegate对象数组。使用这个委托调用捕获异常,继续下一次迭代。
41.闭包和lambda表达式
通过lambda表达式可以访问lambda表达式块外部的变量,称为闭包。
若要创建 Lambda 表达式,需要在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块。 例如,lambda 表达式 x => x * x 指定名为 x 的参数并返回 x 的平方值。 如上面的示例所示,你可以将此表达式分配给委托类型:
"Lambda表达式"是一个特殊的匿名函数,是一种高效的类似于函数式编程的表达式,Lambda简化了开发中需要编写的代码量。它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型,支持带有可绑定到委托或表达式树的输入参数的内联表达式。所有Lambda表达式都使用Lambda运算符=>,该运算符读作"goes to"。Lambda运算符的左边是输入参数(如果有),右边是表达式或语句块。Lambda表达式x => x * x读作"x goes to x times x"。
42.事件
事件基于委托,为委托提供了一种发布/订阅机制。在架构内到处都能看到事件,在window应用程序中,button类提供了click事件,这类事件就是委托。
43.弱事件
通过事件,直接连接到发布程序和侦听器。但垃圾回收有个一个问题,垃圾回收器不能清空侦听器占用的内存,这种强连接可以通过弱事件模式来解决,使用WeakEventManager作为发布程序和侦听器之间的中介。
44.StringBuilder类
可以进行的处理仅限于替换和追加或删除字符串中的文本,但是工作方式非常的高效。
两个重要的属性:
length指定字符串的实际长度
Capacity指定字符串在分配的内存中的最大长度
命名空间:System.Text
在只是连接两个字符串时 string类性能会更好。
45.正则表达式
是一种专门用来处理字符串的语言。
System.Text.RegularExpressions名称空间中Regex类的静态方法Matches()
这个方法的参数是一些输入文本,一个模式和RegexOptions枚举中的一组可选标志。
在正则表达式模式中,也可以把任何字符组合起来(包括元字符和转义序列)
46.集合排序
List
47.队列
队列是元素以先进先出的方式来处理的集合。
队列使用System.Collections.Generic名称空间中的泛型类Queue
Queue
48.栈
最后添加到栈中的元素会最先读取,栈是一个后进先出的容器
用Push()方法在栈中添加元素,用Pop()方法获取最近添加的元素。
Stack
peek()返回栈顶的元素但不删除它。
49.链表
LinkedList
在List
50.有序列表
SortedList
51.字典
表示一种非常复杂的数据结构,这种数据结构允许按照某个键来访问元素,字典也称为映射或散列表。字典的主要特征是能根据键快速查找值,也可以自由添加和删除元素,没有在内存中移动后续元素的性能开销。
主要类是Dictionary
用作字典中键的类型必须重写Object类的GetHashCode()方法。只要字典类需要确定元素的位置,它就要调用GetHashCode()方法
字典的容量是一个素数解答:
字典的内部实现方法。
字典在内部是通过hash表来实现查找的,而查找树在数据结构上采用了有序二叉树与“哈希桶”的一种数据结构来管理元素。
在每个哈希桶里,为了能快速找到一个元素是否存在于此桶,需要为每一个元素进行哈希编码,哈希编码常常采用除余法,也就是说,对于一个给定的a值, 其哈希码h = a mod p, 当这个p是一个素数时,h的冲突机率最少,查找速度也就最快。试想,如果是一个偶数的话,就会有更多情况下的余数冲突。
如果能将a保存到一个桶里的h值对应的下标的话,就可以用h直接定位到元素a,因此,就要求某个桶的容量是p。
这就是为何哈希桶的大小必须是一个素数的原因。
如果你给的构造参数不是素数,构造函数后向后找到大于等于你提供的初始容量的第一个素数,做为其第一个桶的大小。
52.有序字典
SortedDictionary
53.集
包含不重复元素的集合称为“集(set)”。.NET Framework包含两个集HashSet
ISet
54.异或
异或是一个数学运算符。他应用于逻辑运算。
例如:真异或假的结果是真,假异或真的结果也是真,真异或真的结果是假,假异或假的结果是假。就是说两个值相 异结果为真。
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0
55.LINQ
语言集成查询:在C#语言中集成了查询语法,可以用相同的语法访问不同的数据源。LINQ提供了不同数据源的抽象层,所以可以使用相同的语法。
56.LINQ查询
使用这些准备好的列表和实体,进行查询 子句from where orderby descending 和select 都是这个查询中预定义的关键字。
57.扩展方法
可以将方法写入最初没有提供该方法的类中,还可以把方法添加到实现某个特定接口的任何类中,这样多个类就可以使用相同的实现代码。
扩展方法定义为静态方法,第一个参数定义了它扩展的类型。
58.CLR IL 含义
CLR common language runtime 就是运行时相当于一个运行环境(相当于JVM)
IL intermidiate language中间语言,C#先编译成中间语言再在CLR上面执行
.NET运行时任何有意义的操作都是在堆栈上完成的,而不是直接操作寄存器。这就为.NET跨平台打下了基础,通过设计不同的编译器编译相同的IL代码来实现跨平台。对于堆栈我们的操作无非就是压栈和出栈,在IL中压栈通常以ld开头,出栈则以st开头。知道这个后再看上面的指令感觉一下子就豁然开朗了,接下来继续学习的步伐,下面的表格是对于一些常见ld指令。st指令则是将ld指令换成st,功能有压栈变为出栈,有时候会看到在st或ld后加.s这表示只取一个字节。再来看看流程控制,知道压出栈和流程控制后,基本上看出IL的大概意思那就冒闷踢啦。流程控制主要就是循环和分支,下面我写了个有循环和分支的小程序。其中我们用到了加法和比较运算,为此得在这里介绍最基本的三种运算:算术运算(add、sub、mul乘法、div、rem求余);比较运算(cgt大于、clt小于、ceq等于);位运算(not、and、or、xor异或、左移shl、右移shr)。要注意在比较运算中,当执行完指令后会直接将结果1或0压栈,这个过程是自动完成的。对于流程控制,主要是br、brture和brfalse这3条指令,其中br是直接进行跳转,brture和brture则是进行判断再进行跳转。
ldarg
加载成员的参数,如ldarg.0
ldarga
装载参数的地址,注意一般加个a表示取地址
ldc
将数字常量压栈,如ldc.i4.2
ldstr
将字符串的引用压栈
ldloc/ldloca
ldloc将一个局部变量压栈,加a表示将这个局部变量的地址压栈
Ldelem
表示将数组元素压栈
ldlen
将数组长度压栈
ldind
将地址压栈,以地址来访问或操作数据内
59.ScriptRuntime
可以执行存储在文件中的代码段或完整的脚本,可以选择合适的语言引擎,或者让DLR确定使用什么引擎。脚本可以在自己的应用程序域中创建,不仅可以给脚本传入数值并从脚本中传出数值,还可以在脚本中调用在动态对象上创建的方法。
启动ScriptRuntime环境的4个特定步骤:
创建ScriptRuntime对象,设置合适的ScriptEngine,创建ScriptSource,创建ScriptScope。
ScriptRuntime: 创建 DLR 运行环境,这是整个执行过程的起始点,它表示一个全局的执行状态(比如程序集引用等等)。每个应用程序域(AppDomain)中可以启动多个 ScriptRuntime。
ScriptScope: 构建一个执行上下文,其中保存了环境及全局变量。宿主(Host)可以通过创建不同的 ScriptScope 来提供多个数据隔离的执行上下文。
ScriptEngine: DLR 动态语言(比如 IronPython) 执行类,可于解析和执行动态语言代码。
ScriptSource: 操控动态语言代码的类型,我们可以编译(Compile)、读取(Read Code Lines)或运行(Execute)代码。
CompiledCode: 调用 ScriptSource.Compile() 将源代码编译成 CompiledCode,这样多次执行就无需重复编译,从而提高执行性能。
ObjectOperations: 提供了相关方法,允许我们在宿主(Host)中操作 DLR 对象成员(Member)。
该对象使用CreateFromConfiguration()静态方法创建。
60.语法糖
语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
实际上从面向过程到面向对象也是一种语法糖,C语言可以通过它的指针、类型转换,结构体实现面向对象的编程风格,但是C++更进一步的推广了这种风格,更加易用,不过到了C#把OO的风格发挥得淋漓尽致。OO的编程风格对于面向过程来说是不是一种语法糖呢?如果生硬地照此理解,只有计算机硬件指令才不算语法糖,而其他一切利用编译器、汇编器将代码抽象,和自然语言更相近的手段都算语法糖