分类索引:C# 语言和运行时剖析--前言
实例与类型构造器
一.实例构造器(Instance Constructor):构造类型实例的初始化方法
- 作用:初始化类实例.
- 运行时机:初始化实例时
- 最佳用途:初始化实例中所持有的所有字段,使实例字段都具备初始值
- 注意事项:
- 实例构造器不能够被继承。
- 当实例构造器被修饰为private时,不能够被类外部实例化,常用于设计单例模式
二.类型构造器(Type Constructor):设置类型初始化状态的初始化方法
- 作用:控制静态类中成员的初始化时机,可以用于延迟加载
- 运行时机:
- 如果没有显式定义静态构造器,CLR默认为"字段初始化前"(before-field-init)调用类型的静态成员。也就是说,程序员不能控制初始化静态成员的时机。可能在调用前提前很早就初始化了。
- 如果显式定义静态构造器,CLR将会刚好在创建类型的第一个实例之前,或者访问类型的任意一个成员之前调用静态构造器,这种形式叫做精准调用(precise)。程序员可以控制初始化静态成员的时机。
- 注意事项:
- 类型构造器的访问性是private, 但不能用private修饰,且不能使用参数
- CLR保证类型构造器是线程安全的,且在每个AppDomain只执行一次,所以类型构造器适用于初始化类型中需要的任何单例对象。
- 如果显示定义静态构造器,需要注意,首次调用不应该进行大量循环,因为在循环时,程序每次都会去判断有没有调用过静态构造器,这样会影响程序效率。
方法的修饰
实例方法与静态方法
修饰关键字 | 说明 | 备注 |
static | 静态方法是类型功能的一部分,跟对象实例无关 |
|
默认 | 实例方法是对象实例功能的一部分 |
抽象方法、虚方法与重写
abstract | 表示为了构造派生类型的实例,派生类型必须实现并且重写这个方法。 | 抽象方法只能存在于抽象类中,抽象类不能实例化,只能用于派生类型实现 |
virtual | 表示这个成员可由派生类型重写 | |
override | 表示派生类型重写了基类型的成员 |
操作符重载方法
一.定义
操作符重载指对系统定义的一元和二元操作符重新定义的方法.
- 常见的一元操作符包括: !; ++; --; -; 等
- 常见的二元操作符包括: +; -; *; /; ==; &等.
二.准则与示范
- CLR要求操作符重载方法必须修饰为public和static。
- 最佳示范:参考FCL中的System.Decimal类型定义,很好的演示了如何重载操作符并按照微软的指导原则定义友好的方法名。
三.代码实例:
public sealed class Complex { public static Complex operator +(Complex c1, Complex c2) { /// 重载类型的相加操作,实现逻辑部分 } /// <summary> /// 按照微软的指导原则,提供友好方法的代码 /// </summary> /// <param name="c1"></param> /// <param name="c2"></param> /// <returns></returns> public static Complex Add(Complex c1, Complex c2) { return c1 + c2; } }
转换操作符方法
一.缘由:在不同类型之间的转换时,编译器需要知道如何转换的方法
- 当源类型和目标类型都是编译器的基元类型时(例如int, bool, double等),编译器会自动生成转换对象所需的可正常执行的代码.
- 当源类型和目标类型不满足都是基元类型的条件时,编译器也会生成代码,要求CLR执行强制转换。但是,如果源类型和目标类型不存在派生关系时,
很可能强制转换就无法执行
3.需求:在第二种情况时,我们需要定义转换操作符方法
二.概念与准则
- 概念:转换操作符方法用于将对象从一个类型转换为一个不同的类型
- 方法修饰:CLR要求将转换操作符方法修饰为public和static
- 两种不同的操作符转换修饰:
- implicit : 用于修饰隐式转换操作符方法,如果确定转换过程中,不会发生数据丢失,则可以使用隐式转换操作符方法。
- explicit : 用于修饰显式转换操作符方法,如果在转换过程中,可能导致异常或者丢失信息,则应该使用显式转换操作符方法。
- 最佳参考案例:FCL中定义的System.Decimal等基元类型
三.代码示例
/// <summary> /// 自定义有理数类型 /// </summary> public sealed class Rational { public Rational(Int32 number) { /// do someting } public Rational(Single number) { /// do someting } public Int32 ToInt32() { /// do something } public Single ToSingle() { /// do something } public static implicit operator Rational(Int32 num) { return new Rational(num); } public static implicit operator Rational(Single num) { return new Rational(num); } public static explicit operator Int32(Rational r) { return r.ToInt32(); } public static explicit operator Single(Rational r) { return r.ToSingle(); } }
static void Main(string[] args) { Rational r1 = 5; // int32隐式转型为Rational Rational r2 = 2.5F; // single隐式转型为Rational Int32 x = (Int32)r1; // Rational显式转型为Int32 Single s = (Single)r2; // Rational显式转型为Single }
扩展方法
一.功能:
扩展方法用于对已有类型功能的扩展,在FCL中最常见的应用是对LINQ Lambda表达式的一系列扩展。也是LINQ实现的基础特性
二.特性:
- 扩展方法支持智能感知
- 扩展方法支持被子类型继承
三. 准则:
- 扩展方法需要定义在非泛型的静态类型中
- 扩展方法需要被修饰为public static
- 使用扩展方法需要引用(using)定义扩展方法的静态类型的命名空间
四.实践原则:
- 最好针对在继承结构上较为下层的类型/或者接口进行扩展,否则容易引起"智能感知窗口"被填充过多垃圾信息。例如针对System.Object的扩展会被所有类型感知
- C#只支持扩展方法,不支持扩展属性,扩展事件等(虽然他们从原则上说也是方法)
五.代码示例:
public static class ListExtension { public static void ShowItem<T>(this List<T> list) { foreach (var item in list) { Console.WriteLine(item.ToString()); } } }
static void Main(string[] args) { List<Int32> numList = new List<int>(); numList.ShowItem(); }