随笔分类 - Microsoft.Net框架程序设计学习笔记
Microsoft.Net框架程序设计学习笔记(26):委托揭秘
摘要:让我们先看看以下示例代码:using System;using System.Collections.Generic;using System.Text;namespace DelegateTest{ //定义一个委托 public delegate void TestDelegate(int[] array); class Program { //定义一个数组,用于传递委托参数 static int[] array = new int[] { 1, 2, 3, 4, 5 }; //调用委托 static void Load(TestDelegate td) { if (td != null.
阅读全文
Microsoft.Net框架程序设计学习笔记(25):检测定制特性、伪定制特性
摘要:检测定制特性 定义一个特性类型本身没有什么用处,应用程序代码的行为不会因此有任何改变。 在枚举类型上应用Flags特性可以改变System.Enum.ToString、Format方法的行为,这是因为它们会在运行时检测所操作的枚举类型上是否应用了Flags特性。应用程序利用反射技术来查找目标元素上应用了哪些特性。 如果我们是微软公司负责实现Enum类型中Format方法的员工,我们可能会像下面这样来实现它:public static String Format(Type enumType, Object value, String format){ //检测传入的枚举类型是否应用了Flags类
阅读全文
Microsoft.Net框架程序设计学习笔记(24):定义自己的特性
摘要:自定义特性 假设我们是微软的员工,负责为枚举类型添加位标记支持。要实现这一点,我们首先定义一个FlagsAttribute类型: namespace System{ [AttributeUsage(AttributeTargets.Enum, Inherited = false)] public class FlagsAttribute : System.Attribute { public FlagsAttribute(){} }} 注意FlagsAttribute类型继承自System.Attribute,这使该特性成为一个与CLS兼容的定制特性。另外,所有的非抽象特性都必须具有publ.
阅读全文
Microsoft.Net框架程序设计学习笔记(23):定制特性概述
摘要:定制特性仅仅是为目标元素提供关联附加信息的一种方式。编译器的工作只是将这些附加信息存放在托管模块的元数据中而已。大多数特性对编译器没有任何意义。编译器仅仅只是检测源代码中的定制特性,然后产生相应的元数据。 CLR允许将特性应用于任何可在一个文件的元数据中表示的元素(如:TypeDef、MethodDef、ParamDef、FieldDef、PropertyDef、EventDef、AssemblyDef、ModuleDef),也可以应该到元数据引用表中的条目上(如:AssemblyRef、ModuleRef、TypeRef、MemberRef),还可以应用到其他一些元数据中(如:安全许可、导.
阅读全文
Microsoft.Net框架程序设计学习笔记(22):接口与完全限定接口名技巧
摘要:接口仅仅是一个包含着一组虚方法的抽象类型。 接口中也可以定义事件、无参属性、含参属性(即索引器),因为它们都不过是映射到方法上的语法缩写而已。 接口类型的名称要加一个大写的字母I前缀。接口定义允许使用修饰符--如public、protected、private、internal。 一个值类型可以实现一个或多个接口,但当我们将一个值类型实例转型为一个接口类型时,该值类型实例必须被执行装箱。因为接口总被认为是引用类型,且它们定义的方法总是虚方法。未装箱的值类型没有指向类型方法表的指针。 当我们创建可扩展的应用程序时,接口应该处于中心位置。假设我们正在编写一个应用程序,且希望其他人创建的类型能被我.
阅读全文
Microsoft.Net框架程序设计学习笔记(21):数组的传递与返回、创建下限非0数组、快速访问数组
摘要:数组的传递与返回 如果我们定义了一个返回数组引用的方法,而在某些情况下数组又不含任何元素,那么我们的方法即可返回一个null,也可返回一个长度为0的数组引用。当我们实现这样的方法时,微软强烈建议我们让该方法返回一个0长的数组,因为这样会简化调用该方法的开发人员的编码工作。 同理,我们应该以同样的方式来处理字段。创建下限非0的数组 使用Array.CreateInstance静态方法可以动态创建下限非0的数组。 示例代码: 可使用Array.GetLowerBound和Array.GetUpperBound方法来获取此类数组的上下限索引号,以方便编码。快速访问数组 我们每次访问一个数组中的元素时
阅读全文
Microsoft.Net框架程序设计学习笔记(20):数组Array基类介绍、数组转型
摘要:数组 所有的数组类型都隐含继承自System.Array,Array本身又继承自Object。 每个数组都有一些额外的负载信息,这些信息包括数组的维数、每一维的最低下限索引、每一维的长度、每一个元素的类型。 交错数组的定义示例: Point[][] myPolygons = new Point[2][]; myPolygons[0] = new Point[10]; myPolygons[1] = new Point[20]; 交错数组与CLS是不兼容的,CLS不允许一个数组的元素类型为Array,所以它不能在不同的编程语言中传递。数组基类Array Array实现了以下几个接口:ICl
阅读全文
Microsoft.Net框架程序设计学习笔记(19):枚举类型与位标记
摘要:枚举类型 当编译一个枚举类型时,C#编译器会将其中的每个符号转变为类型的一个常数字段。 枚举类型就是一个定义了一组常数字段的结构而已。这些字段编译后会被存放在生成模块的元数据中,且可以通过反射来访问。 Enum的静态方法:static Type Enum.GetUnderLyingType(Type enumType)。该方法返回用于保存枚举类型实例值的基础类型。每个枚举类型都有一个基础类型,它们可以是byte、sbyte、short、ushort、int(C#选用的默认值)、uint、long或ulong。 我们可以在定义一个枚举类型的时候,让其中多个符号有着相同的数值。但当将一个数值转换为
阅读全文
Microsoft.Net框架程序设计学习笔记(18):StringBuilder、字符串特定格式与语言文化、字符串编码与解码
摘要:StringBuilder 为了获得更高的性能,StringBuilder的方法并不保证线程安全。如果我们的程序需要对StringBuilder对象做多线程操作,那么我们必须显式添加线程同步代码。字符串特定格式与语言文化 如果我们希望自己的类型能为调用者提供格式和语言文化选择的话,我们就应该使其实现System.IFormattable接口: public interface IFormattable { String ToString(String format, IFormatProvider formatProvider); } format参数告诉方法应该怎样来格式化对象;format
阅读全文
Microsoft.Net框架程序设计学习笔记(17):字符串驻留
摘要:关于回车、换行 String s = "Hi\r\nthere."; 以上代码将回车、换行字符硬编码到字符串中,但更加好的做法是使用System.Enviroment类型提供的一个名为NewLine的只读属性。 示例代码: String s = "Hi" + Enviroment.NewLine + "there."; 这样做的好处是,NewLine属性依赖于特定平台,根据底层平台的不同,它的返回值也不同。在Windows系统上运行时,该属性返回的字符串为"\r\n"。如果将CLR移植到UNIX系统上,NewLin
阅读全文
Microsoft.Net框架程序设计学习笔记(16):显式控制事件注册
摘要:有时我们会感到编译器自动产生的add和remove方法不够理想。如:我们需要频繁地添加或移除委托实例,同时我们又知道我们的程序是在单线程环境下运行,这时再对包含委托实例的对象进行同步访问的话就会损伤应用程序性能。 C#编译器允许我们显式实现add和remove访问器方法。示例代码如下:public class MailManager{ public delegate void MailMsgEventHandler(Object sender, MailMsgEventArgs args); //显式定义一个私有委托链表字段 private MailMsgEventHandler mailM.
阅读全文
Microsoft.Net框架程序设计学习笔记(15):事件之原理分析
摘要:完整定义一个事件的方法 以Mail发送为例:定义一个类型用于保存所有需要发送给事件通知接受者的附加信息。按.Net框架约定,所有保存事件信息的类型都应该继承自System.EventArgs,且类型的名称应该EventArgs结束。 public class MailMsgEventArgs : EventArgs { public readonly string from, to, subject, body; public MailMsgEventArgs(string from, string to, string subject, string body) { this.from =
阅读全文
Microsoft.Net框架程序设计学习笔记(14):属性
摘要:当定义一个属性时,编译器会在生成的托管模块中产生以下3项:一个表示属性的get访问器的方法。只有为属性定义了get访问器方法时,才有这一项。一个表示属性的set访问器的方法。只有为属性定义了set访问器方法时,才有这一项。一个位于托管模块元数据中的属性定义,不管是只读、只写、或读写属性都有这一项。
阅读全文
Microsoft.Net框架程序设计学习笔记(13):虚方法调用机理
摘要:CLR提供了两个IL指令来调用方法:call和callvirt。 call指令根据引用变量的类型来调用一个方法。 callvirt指令根据引用变量指向的对象类型来调用一个方法。 当编译源代码时,编译器知道代码中是否在调用一个虚方法,并据此产生call或callvirt指令。产生call而不是callvirt会提高代码的性能,因为CLR不必检查引用对象的实际类型。 不管最终是通过call还是callvirt来调用一个实例方法,所有的实例方法调用都会接受一个隐藏的this指针作为方法的第一个参数,其中this指针指向当前正在操作的对象。
阅读全文
Microsoft.Net框架程序设计学习笔记(12):操作符重载、转换操作符、引用参数、可变数目参数
摘要:操作符重载方法: CLR对操作符重载一无所知,它甚至都不认识操作符是什么。我们选择的编译语言定义了每个操作符的含义,以及当遇到它们时产生什么样的代码。 如在C#中,应用于基元数值类型上的+符号会使编译器产生将两个数相加的代码。 虽然CLR对操作符一无所知,但它却规范了编程语言应该怎样提供操作符重载。对于CLR来讲,重载操作符仅仅是一些方法而已。 以下代码:class Complex{ public static Complex operator+(Complex c1, Complex c2) {......}} 编译器会产生一个名为op_Addition的方法定义,该方法定义条目上有一个sp
阅读全文
Microsoft.Net框架程序设计学习笔记(11):类型构造器
摘要:除实例构造器外,CLR还支持类型构造器(又称静态构造器、类构造器、类型初始化器)。类型构造器用于设置一个类型的初始状态。默认情况下,一个类型中没有定义类型构造器,只能手动定义。且类型构造器不能有任何参数。 示例代码如下:class SomeRefType{ //当SomeRefType第一次被访问时执行 static SomeRefType() {}}struct SomeValType{ //当SomeValType第一次被访问时执行 static SomeValType() {}} 类型构造器不允许添加任何访问限制符,它的访问限制被自动设为私有方式。类型构造器的调用由CLR负责,CLR会.
阅读全文
Microsoft.Net框架程序设计学习笔记(10):实例构造器
摘要:创建一个引用类型的实例时,系统分以下三步骤:首先为该实例分配内存。初始化对象的附加成员(即方法表指针和一个SyncBlockIndex)调用类型的实例构造器设置对象的初始状态。 以下情况,类型实例的创建不需要调用实例构造器。调用Object的MemberwiseClone方法,它将执行以下几步:为对象分配内存,初始化对象的附加成员,将源对象的字节拷贝到新创建的对象中。反序列化一个对象时,通常也不会调用构造器。 内联方式初始化实例字段的语法,如下:class ClassA{ int i = 5;} 实际上内联方式初始化实例字段的简化语法都被转换成了构造器中的代码。这时,如果在构造器中又对字段进.
阅读全文
Microsoft.Net框架程序设计学习笔记(9):常数与只读字段
摘要:常数是在编译时嵌入代码中,所以常数在运行时不再需要任何内存分配。我们不能获取常数的地址,或以引用的方式来传递一个常数。 如果要求一个模块中的数值能够在运行时而非编译时被另一个模块获取,那就不应该使用常数,因为常数在编译时就已经被嵌入到程序的IL代码中了。这时,应该使用只读字段。 只读字段只能在构造器内被赋值,且在构造器内只读字段可以多次被赋值。 对于静态只读字段只能在静态构造器内赋值,静态构造器在该类型初次被引用时执行。
阅读全文
Microsoft.Net框架程序设计学习笔记(8):对象散列码、对象克隆
摘要:对象的散列码: object提供了一个GetHashCode虚方法,我们可以从任何对象上得到一个Int32类型的散列码。 如果我们定义了一个类型,且重写了Equals方法,我们就应该重写GetHashCode方法。因为Hashtable类型的实现要求任何两个相等的对象都必须有相同的散列值。 object的GetHashCode方法返回的是一个在应用程序域范围内确保唯一的数值,该数值在对象的整个生存期中保证不会改变。但在对象被执行垃圾收集后,这个唯一的数值可以被重新利用作为一个新的对象的散列码。 ValueType中实现的GetHashCode方法使用反射来返回定义在类型中第一个实例字段的散列码
阅读全文
Microsoft.Net框架程序设计学习笔记(7):重写Object.Equals方法
摘要:System.Object类型提供了名为Equals的虚方法,目的为判断两个对象是否有相同的“值”。.Net框架类库(FCL)中许多方法在内部都调用了Equals方法(如:Array的IndexOf方法、ArrayList的Contains方法)。对于没有显式重写Equals的类型,Object(或重写了Equals方法的最近的那基类)提供的实现将被继承。以下代码展示了System.Object类型中的Equals方法实现: class object { public virtual Boolean Equals(object obj) { //如果引用指向的是同一对象,肯定相等 if (t.
阅读全文