![](https://img-blog.csdnimg.cn/20201014180756738.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
CLR via C# 学习笔记
码农小飞飞
在手游开发的路上越走越远!
展开
-
CLR via C# 委托 C#为委托提供的简化语法
许多程序员因为语法奇怪而对委托有抗拒感。例如:其中button_click是方法,像这样:第一行代码的思路是向按钮控件登记button_click方法的地址,以便在按钮被单击时调用方法。许多程序员认为,仅仅为了指定button_click方法的地址,就构造一个EventHander委托对象,这显得有点不可思议。然而,构造EventHander委托对象是CLR要求的,因为这个对象提供了一个包装器,可确保(被包装的)方法只能以类型安全的方式调用。这个包装器还支持调用实例方法和委托链。..原创 2020-07-07 17:33:02 · 408 阅读 · 0 评论 -
CLR via C# 委托 委托定义不要太多(利用泛型委托)
Microsoft在刚开始开发.NET Framework的时候引入了委托的概念。开发人员在FCL 中添加类时,凡是有回调方法的地方都定义了新的委托类型。随着时间推移定义了许多委托。仅在MSCorLib.dll中就有近50个,举例几个:可以看到这几个委托的共同点。它们其实都是一样的:这些委托类型的变量所引用的方法都是获取一个object,并返回void 。没理由定义这么多委托类型,留一个就行。.NET Framwork现在支持泛型,所以实际只需几个泛型委托(在System命名空间中定义)就.原创 2020-07-03 15:50:49 · 200 阅读 · 0 评论 -
CLR via C# 委托 用委托回调多个方法(委托链)
委托链是委托对象的集合。可利用委托链调用集合中的委托所代表的全部方法。构造了三个委托对象并让fb1,fb2和fb3分别引用每个对象。指向Feedback委托对象的引用变量fbChain旨在引用委托链(或者说委托对象集合),这些对象包装了可回调的方法。fbChain初始化为null,表明目前要回调的方法。使用Delegate类的公共静态方法Combine将委托添加到链中:1.Combine方法发现视图合并的是null和fb1。在内部,Combin...原创 2020-07-01 14:33:10 · 432 阅读 · 0 评论 -
CLR via C# 委托 委托揭秘
从表面看,委托似乎很容易使用:用C#的delegate关键字定义,用熟悉的new操作符构造委托实例,用熟悉的方法调用语法来调用函数(用引用了委托对象的变量代替方法名)。编译器和CLR在幕后做了大量工作来隐藏复杂性。首先重新审视这一行代码:看到这行代码后,编译器实际会像下面这样定义一个完整的类:(ILDasm.exe)编译器定义的类有4个方法:一个构造器、Invoke、BeginInvoke和EndInvoke。(所有委托类型都派生自MulticastDelegate)。重原创 2020-06-29 18:52:04 · 235 阅读 · 0 评论 -
CLR via C# 委托 初识委托
Microsoft.NET Framework 通过委托来提供回调函数机制。不同于其他平台(比如非托管堆C++)的回调机制,委托的功能要多得多。例如,委托确保回调方法是类型安全的(这是CLR最重要的目标之一)。委托还允许顺序调用多个方法,并支持调用静态方法和实例方法。using System;using System.Windows.Forms;namespace CLRviaCSharp{ //声明一个委托类型,它的实例引用一个方法, //该方法获取一个int参数,返回voi原创 2020-06-12 15:59:21 · 181 阅读 · 0 评论 -
CLR via C# 数组 数组的传递和返回
数组作为实参传给方法时,实际传递的是对该数组的引用。因此,被调用的方法能修改数组中的元素。如果不想被修改,必须生成数组的拷贝并将拷贝传给方法。注意,Array.Copy方法执行的是浅拷贝。换言之,如果数组元素是引用类型,新数组将引用先有的对象。类似的,有的方法会返回数组的引用。如果方法构造并初始化数组,返回数组引用是没有问题的。但假如方法返回的是对字段所维护的一个内部数组的引用,就必须决定是否想让该方法的调用者直接访问这个数组及其元素。如果是,就可以返回数组引用。但更常见的情况是,你并不希望方法的调用者原创 2020-06-11 19:21:09 · 1102 阅读 · 0 评论 -
CLR via C# 数组 所有数组都隐式实现IEnumerable,ICloneable和IList
许多方法都能操纵各种各样的集合对象,因为他们声明为允许获取IEnumerable,ICloneable和IList等参数。可将数组传递给这些方法,因为 System.Array 之所以实现这些非泛型接口,是因为这些接口将所有元素都视为 System.Object 。然而,最好是让 System.Array 实现这些接口的泛型形式,提供更好的编译时类型安全性和更好的性能。不过,由于涉及多维数组和非0基数组的问题,CLR团队不希望 System.Array 实现IEnumerable<T>,I.原创 2020-06-11 17:10:45 · 232 阅读 · 0 评论 -
CLR via C# 数组 所有数组都隐式派生自System.Array
像下面这样数组变量:CLR会自动为AppDomain创建一个FileStream[] 类型。该类型隐式派生自System.Array 类型;因此,System.Array 类型定义的所有实例方法和属性都能通过fileStreams 变量调用。这极大方便了数组处理,因为System.Array 定义了许多有用的实例方法和属性,比如 Clone,CopyTo,GetLength,GetLongLength,GetLowerBound,GetUpperBound,Length,Rank等。...原创 2020-06-11 15:50:17 · 221 阅读 · 0 评论 -
CLR via C# 数组 数组转型
对于元素为引用类型的数组,CLR允许将数组元素从一种类型转型另一种。成功转型要求数组维数相同,而且必须从元素源类型到目标类型的隐式或显示转换。CLR不允许将值类型元素的数组转型为其他任何类型。(不过,可用Array.Copy方法创建新数组并在其中填充元素来模拟这种效果。)Array.Copy的作用不仅仅是将元素从一个数组复制到另一个。Copy方法还能正确处理内存的重叠区域。Copy方法还能再复制每个数组元素时进行必要的类型转换:1.将值类型的元素装箱为引用类型的元素。比如将一个i原创 2020-05-26 17:30:49 · 584 阅读 · 0 评论 -
CLR via C# 数组 初始化数组元素
创建数组对象,初始化数组元素。C# 允许用一个语句做这两件事情:大括号中的以逗号分隔的数据项称为数组初始化器(array initializer)。每个数据项都可以是一个任意复杂度的表达式;在多维数组的情况下,则可以是一个嵌套的数组初始化器。可以利用 C# 的 隐式类型的局部变量功能:可利用 C# 的隐式类型的数组功能让编译器推断数组元素的类型:上一行代码中,编译器检查数组中用于初始化数组元素的表达式的类型,并选择所有元素最接近的公共基类来作为数组的类型。在本例中,编原创 2020-05-18 19:34:19 · 433 阅读 · 0 评论 -
CLR via C# 数组 简介
数组是允许多个数据项作为集合来处理的机制。CLR支持一维、多维和交错数组(即数组构成的数组)。所有数组类型都隐式地从System.Array 抽象类派生,后者有派生自System.Object。这意味着数组始终是引用类型,是在托管堆上分配的。在应用程序的变量或字段中,包含的是对数组的引用,而不是包含数组本身的元素。第一行代码声明myInts 变量,它能指向包含 int 值的一维数组。myInts 刚开始被设为 null ,因为当时还没有分配数组。第二行代码分配了含有100个int 值的数组.原创 2020-05-18 16:12:05 · 424 阅读 · 0 评论 -
CLR via C# 枚举类型和位标志
枚举类型枚举类型(enumerated type)定义了一组“符号名称/值”配对。例如:也可以写程序用0表示白色,用1表示红色。不过,不应该使用这些数字硬编码到代码中,而应使用枚举类型。//--1.枚举类型使程序更容易编写、阅读和维护。有了枚举类型,符号名称可在代码中随便使用,程序员不用费心思量每个硬编码的含义。而且,一旦与符号名称对应地值发生改变,代码也可以简单地重新编译,不需要对源代码进行任何修改。此外,文档工具和其他实用程序能向开发人员显示有意义的符号名称。2.枚举类型是强原创 2020-05-14 19:31:20 · 355 阅读 · 0 评论 -
CLR via C# 高效率构造字符串 System.Text.StringBuilder
由于 String 类型代表不可变字符串,所以 FCL 提供了System.Text.StringBuilder 类型对字符串和字符进行高效动态处理,并返回处理好的String 对象。可将StringBuilder 想象成创建String 对象的特殊构造器。你的方法一般应获取String 参数而非StringBuilder 参数。从逻辑上说,StringBuilder 对象包含一...原创 2020-05-08 11:00:43 · 331 阅读 · 0 评论 -
CLR via C# System.String 类型 检查字符串中的字符和文本元素
虽然字符串比较对于排序或测试相等性很有用,但有时只是想检查一下字符串中的字符。String 类型为此提供了几个属性和方法,包括 Length,Chars(一个C#索引器),GetEnumerator,ToCharArray,Contains,IndexOf,LastIndexOf,IndexOfAny和LastIndexOfAny。System.Char 实际代表一个16位 Unicode 码...原创 2020-01-18 10:57:55 · 265 阅读 · 0 评论 -
CLR via C# System.String 类型 字符串池
编译源代码时,编译器必须处理每个字面值(literal)字符串,并在托管模块的元数据中嵌入。同一个字符串在源代码中多次出现,把它们都嵌入元数据会使生成的文件无畏地增大。为了解决这个问题,许多编译器(包括C#编译器)只在模块的元数据中只将字面值字符串写入一次。引用该字符串的所有代码都被修改修改成引用元数据中的同一个字符串。编译器将单个字符串的多个实例合并成一个实例,能显著减少模块的大小。...原创 2020-01-17 19:06:31 · 132 阅读 · 0 评论 -
CLR via C# System.String 类型 字符串留用
检查字符串相等性是应用程序的常见操作,也是一种可能严重损害性能的操作。执行序号(ordinal)相等性检查时,CLR快速测试两个字符串是否包含相同数量的字符。答案否定,字符串肯定不相等;答案肯定,字符串则可能相等。然后,CLR必须比较每个单独字符才能最终确认。而执行对语言文化敏感的比较时,CLR必须比较所有单独的字符,因为两个字符串即使长度不同也可能是相等。此外,在内存中复制同一个字符...原创 2020-01-17 19:00:44 · 267 阅读 · 0 评论 -
CLR via C# System.String 类型 比较字符串
“比较”或许是最常见的字符串操作。一般因为两个原因要比较字符串:判断相等性或者排序。判断字符串相等性或者排序时,强烈建议调用 String 类定义的以下方法之一:排序时应该总是执行区分大小写的比较。原因是假如只是大小写不同的两个字符串被视为相等,那么每次排序都可能按不同顺序排列,用户会感到困惑。其中CompareOptions 定义如下:接受C...原创 2020-01-17 15:11:45 · 228 阅读 · 0 评论 -
CLR via C# System.String 类型 字符串是不可变的
String 对象最重要的一点就是不可变(immutable)。也就是说,字符串一经创建便不能更改,不能变长、变短或修改其中的任何字符。使字符串不可变有几个方面的好处。首先,它允许在一个字符串上执行各种操作,而不实际地更改字符串:ToUpperInvariant 返回一个新的字符串;它没有修改字符串 s 的字符。在ToUpperInvariant 返回的字符串上执行的Substri...原创 2020-01-16 20:46:16 · 155 阅读 · 0 评论 -
CLR via C# System.String 类型 构造字符串
许多编程语言(包括C#)都将String视为基元类型---也就是说。编译器允许在源代码中直接使用字面值(literal)字符串。编译器将这些字符串放到模块的元数据中,并在运行时加载和利用它们。C#不允许使用 new 操作符从字面值字符串构造String对象:相反,必须使用以下简化语法:编译代码并检查 IL :用于构造对象的新实例的IL指令是 newobj 。但上述 I...原创 2020-01-16 20:12:42 · 274 阅读 · 0 评论 -
CLR via C# System.String 类型
在任何应用程序中,System.String都是用得最多的类型之一。一个String代表一个不可变(immutable)的顺序字符集。String类型直接派生自Object,所以是引用类型。因此,String对象(它的字符数组)总是存在于堆上,永远不会跑到线程栈。String类型还实现了几个接口(IComparable, ICloneable, IConvertible, IEnumerable,...原创 2020-01-18 11:12:29 · 165 阅读 · 0 评论 -
CLR via C# 字符 System.Char
在.NET Framework中,字符总是表示成16位Unicode代码值,这简化了国际应用程序的开发。每个字符都是System.Char结构(一个值类型)的实例。System.Char类型很简单,提供了两个公共只读常量字段:MinValue和MaxValue。为Char的实例调用静态GetUnicodeCategory方法返回System.Globalization.UnicodeCat...原创 2020-01-14 16:55:29 · 465 阅读 · 0 评论 -
CLR via C# 设计时:用基类还是接口
应该设计基类还是接口不能一概而论。1.IS-A(“属于”)对比CAN-DO(“能做某事”)关系类型只能继承一个实现。如果派生类型和基类型建立不起IS-A关系,就不用基类而用接口。接口意味着CAN-DO关系。如果多种对象类型都“能”做某事,就为它们创建接口。例如,一个类型能将自己的实例转换为另一个类型(IConcertible),一个类型能序列化自己的实例(ISerializable)。注意...原创 2020-01-14 11:03:15 · 169 阅读 · 0 评论 -
CLR via C# 接口 谨慎使用显式接口方法实现
使用 EIMI 也可能造成一些严重后果,所以应该尽量避免使用 EIMI 。幸好,泛型接口可帮助我们在大多数时候避免使用 EIMI 。但有时仍然需要它们。(比如实现具有相同名称和签名的两个接口方法时)EIMI 最主要的问题如下:1.没有文档解释类型具体如何实现一个 EIMI 方法,VS也没有“智能感知”支持。2.值类型的实例在转换成接口时装箱。3.EIMI 不能由派生类型调用。/...原创 2020-01-13 19:48:33 · 161 阅读 · 0 评论 -
CLR via C# 接口 用显式接口方法实现来增强编译时类型安全性
接口很好用,它们定义了在类型之间进行沟通的标准方式。遗憾的是,有时由于不存在泛型版本,所以仍需实现非泛型接口。接口的任何方法接受System.Object类型的参数或返回System.Object类型的值,就会失去编译时的类型安全性,装箱也会发生。本章将介绍如何用“显式接口方法实现”(EIMI)在某种程度上改善这个局面。这是一个常用的接口。该接口定义了接受一个System.Obje...原创 2020-01-13 17:26:33 · 110 阅读 · 0 评论 -
CLR via C# 接口 实现多个具有相同方法名和签名的接口
定义实现多个接口的类型时,这些接口可能定义了具有相同名称和签名的方法。由于这个类型必须实现多个接口的Get方法,所以要告诉C#编译器每个Get方法对应地是哪个接口的实现。代码在使用SomeType对象时必须将其转换为具体的接口才能调用所需的方法。...原创 2020-01-13 15:40:35 · 381 阅读 · 0 评论 -
CLR via C# 接口 泛型和接口约束
将泛型类型参数约束为接口的好处。第一个好处在于,可将泛型类型参数约束为多个接口。这样一来,传递的参数的类型必须实现全部接口约束。定义方法参数时,参数的类型规定了传递的实参必须是该类型或者它的派生类型。如果参数的类型是接口,那么实参可以是任意类类型,只要改类型实现了接口。使用多个接口约束,实际是表示向方法传递的实参必须实现多个接口。事实上,如果将T约束为一个类和两个接口,就表示传递的...原创 2020-01-13 15:25:25 · 467 阅读 · 0 评论 -
CLR via C# 接口 泛型接口
C#和CLR所支持的泛型接口为开发人员提供了许多非常出色的功能。首先,泛型接口提供了出色的编译时类型安全。有的接口定义的方法使用了object参数或object返回类型。在代码中调用这些接口方法时,可传递对任何类型的实例的引用。但这通常不是我们期望的。接口方法理想情况下应使用强类型。这正是FCL为什么包含泛型IComparable<inT>接口的原因。泛型接口的第...原创 2020-01-13 14:49:55 · 152 阅读 · 0 评论 -
CLR via C# 接口 隐式和显式接口方法实现(幕后发生的事情)
类型加载到CLR中时,会认为该类型创建并初始化一个方法表。在这个方法表中,类型引入的每个新方法都有对应地记录项;另外,还为该类型继承的所有虚方法添加了记录项。继承的虚方法既有继承层次结构中的各个基类型定义的,也有接口类型定义的。类型的方法表将包含以下方法的记录项。1.object(隐式继承的基类)定义的所有虚实例方法。2.IDisposable(继承的接口)定义的所有接口方法。...原创 2020-01-13 11:23:23 · 141 阅读 · 0 评论 -
CLR via C# 接口 继承接口
比较接口:使用:C#编译器要求将实现接口的方法标记为public。CLR要求将接口方法标记为virtual。不将方法显式标记为virtual,编译器会将它们标记为virtual何sealed;这会阻止派生类重写接口方法。将方法显式标记为virtual,编译器就会将该方法标记为virtual(并保持它的非密封状态),使派生类能重写它。派生类不能重写sealed的接口方法。但...原创 2020-01-09 11:59:58 · 178 阅读 · 0 评论 -
CLR via C# 接口 定义接口
接口对一组方法签名进行了统一命名。接口还能定义事件、无参属性和有参属性(C#的索引器)。这些东西本质上都是方法,它们只是语法上的简化。接口不能定义任何构造器方法,也不能定义任何实例字段。//--虽然CLR允许接口定义静态方法、静态字段、常量和静态构造器,但符合CLS标准的接口绝不允许,因为有的编程语言不能定义或访问它们。C#禁止接口定义任何一种这样的静态成员。//--C#用...原创 2020-01-08 14:57:50 · 260 阅读 · 0 评论 -
CLR via C# 接口 类和接口继承
CLR不支持多继承,因此所有托管编程语言也支持不了。CLR只是通过接口提供了缩水版的多继承。Microsoft.NET Framework 提供了System.Object类,它定义了4个公共实例方法:ToString,Equals,GetHashCode和GetType。该类是其他所有类的跟或者说终极基类。换言之,所有类都继承了object的4个实例方法。这还意味着只要代码能操作obje...原创 2020-01-07 11:01:51 · 183 阅读 · 0 评论 -
CLR via C# 泛型 其他可验证问题
此处讨论几个特殊的代码构造。由于可验证问题,这些代码构造在和泛型共同使用时,可能产生不可预期的行为。另外,还讨论如何利用约束使代码重新变得可以验证。1.泛型类型变量的转型将泛型类型的变量转型为其他类型时非法的,除非转型为与约束兼容的类型。编译器报错。为了修改代码使其能通过编译,可以先转型为object:虽然代码可以编译,但CLR仍有可能在运行时抛出InvalidCastEx...原创 2020-01-07 10:37:26 · 104 阅读 · 0 评论 -
CLR via C# 泛型 约束
编译泛型代码时,C#编译器会进行分析,确保代码适用于当前已有或将来可能定义的任何类型。这个方法适用于任何类型。无论T是引用类型,是值类型或枚举类型,还是接口或委托类型,它都能工作。这个方法适用于当前存在的所有类型,也适用于将来可能定义的任何类型,因为所有类型都支持对object类型的变量的赋值,也支持对object类型定义的方法的调用(比如ToString和Equals)。看下面这个方...原创 2020-01-06 17:26:55 · 152 阅读 · 0 评论 -
CLR via C# 泛型 泛型方法
定义泛型类、结构或接口时,类型中定义的任何方法都可引用类型指定的类型参数。类型参数可作为方法参数、方法返回值或方法内部定义的局部变量的类型使用。然而,CLR还允许方法指定它自己的类型参数。这些参数也可作为参数、返回值或局部变量的类型使用。在上面例子中,GenericType类定义了类型参数T,Converter方法也定义了自己的类型参数TOutput。这样的GenericType可以处理任...原创 2020-01-06 12:03:41 · 130 阅读 · 0 评论 -
CLR via C# 泛型 委托和接口的逆变和协变泛型类型参数
委托的每个泛型类型参数都可以标记为协变量或逆变量。(协变性指定返回类型的兼容性,而逆变性指定参数的兼容性)利用这个功能,可将泛型委托类型的变量转换为相同的委托类型(但泛型参数类型不同)。泛型类型参数可以是以下任何一种形式。1.不变量(invariant) 意味着泛型类型参数不能改变。2.逆变量(contravariant)意味着泛型类型参数可以从一个类更改为它的某个派生类。在C#是用in关...原创 2020-01-04 17:31:06 · 152 阅读 · 0 评论 -
CLR via C# 泛型 泛型委托
CLR支持泛型委托,目的是保证任何类型的对象都能以类型安全的方式传给回调方法。此外,泛型委托允许值类型实例在传给回调方法时不进行任何装箱。委托实际只是提供了4个方法的一个类定义。4个方法包括一个构造器、一个Invoke方法,一个BeginInvoke方法和一个EndInvoke方法。如果定义的委托类型指定类型参数,编译器会定义委托类的方法,用指定的类型参数替换方法的参数和返回值类型。IL...原创 2020-01-03 23:15:25 · 113 阅读 · 0 评论 -
CLR via C# 泛型 泛型接口
泛型的主要作用就是定义泛型的引用类型和值类型。然而,对泛型接口的支持对CLR来说也很重要。没有泛型接口,每次用泛型接口(例如IComparable)来操纵值类型都会发生装箱,而且会失去编译时的类型安全。这将严重制约泛型类型的应用范围。因此,CLR提供了对泛型接口的支持。引用类型或值类型可指定类型实参实现泛型接口。也可保持类型实参的未指定状态来实现泛型接口。下面的实例实现了上述泛型接口,而且...原创 2020-01-03 17:14:28 · 122 阅读 · 0 评论 -
CLR via C# 泛型 泛型基础结构
泛型在CLR2.0中加入。为了在CLR中加入泛型,许多人花费了大量时间来完成这个大型任务。具体地说,为了使泛型能够工作,Microsoft必须完成以下工作。1.创建新的IL指令,使之能够识别类型实参。2.修改现有元数据表的格式,以便表示具有泛型参数的类型名称和方法。3.修改各种编程语言(C#等)来支持新语法,允许开发人员定义和引用泛型类型和方法。4.修改编译器,使之能生成新的IL指...原创 2020-01-03 14:03:02 · 136 阅读 · 0 评论 -
CLR via C# 泛型 FCL中的泛型
泛型最明显的应用就是集合类。FCL在System.Collections.Generic和System.Collections.ObjectModel命名空间中提供了多个泛型集合类。System.Collections.Concurrent命名空间则提供了线程安全的泛型集合类。Microsoft建议使用泛型集合类,不建议使用非泛型集合类。这是出于几方面的考虑。首先,使用非泛型集合类,无法像使用泛型...原创 2020-01-03 10:59:11 · 144 阅读 · 0 评论 -
VLR via C# 泛型
面向对象的开发人员都深谙这种编程方式的好处。其中一个好处就是“代码重用”,它极大提高了开发效率。泛型(generic)是CLR和编程语言提供的一种特殊机制,它支持另一种形式的代码重用,即“算法重用”。简单说,开发人员先定义好算法,比如排序、搜索、交换、比较或者转换等。但是,定义算法的开发人员并不设定该算法要操作什么数据类型;该算法可广泛地应用于不同类型的对象。然后,另一个开发人员只要指定了...原创 2020-01-03 10:44:35 · 133 阅读 · 0 评论