C#基础-第8章:方法
第2部分:第8章:方法P(161) 8.1 本章内容: 实例构造器(引用类型) 实例构造器和结构(值类型) 类型构造器 操作符重载方法 扩展方法 分部方法
#if !DEBUG #pragma warning disable 414, 169 #endif using System; using System.Diagnostics; using System.Text; using System.Collections.Generic; namespace Example1 { internal sealed class SomeType { private Int32 m_x = 5; } } namespace Example2 { #pragma warning disable 169 internal sealed class SomeType //P(163) { private Int32 m_x = 5; private String m_s = "Hi there"; private Double m_d = 3.14159; private Byte m_b; // 下面是一些构造器 public SomeType() { /* ... */ } public SomeType(Int32 x) { /* ... */ } public SomeType(String s) { /* ...; */ m_d = 10; } } #pragma warning restore 169 } namespace Example3 { internal sealed class SomeType { // 不要显式初始化下面的字段 private Int32 m_x; private String m_s; private Double m_d; private Byte m_b; //该构造器将所有字段都设为默认值 //其他所有构造器都有显式调用该构造器 private void SetFieldDefaults() { m_x = 5; m_s = "Hi there"; m_d = 3.14159; m_b = 0xff; } // 该构造器将所有字段都设为默认值 public SomeType() { SetFieldDefaults(); } // 该构造器将所有字段都设为默认值,然后修改m_x的值 public SomeType(Int32 x) { SetFieldDefaults(); m_x = x; } // 该构造器将所有字段都设为默认值,然后修改m_x的值, 然后修改 m_s. public SomeType(String s) { SetFieldDefaults(); m_s = s; } // 该构造器将所有字段都设为默认值, 然后修改 m_x 和 m_s. public SomeType(Int32 x, String s) { SetFieldDefaults(); m_x = x; m_s = s; } } } //这是值类型的构造器 internal struct SomeValType { /** 静态构造器 ,C# 会自动笔记为private ,静态构造器中不允许出现访问修饰符***/ static SomeValType() { //值类型的构造器,不会执行,引用类型静态构造器才会首次执行 Console.WriteLine("这句话永远不会显示"); } public Int32 m_x; } public sealed class Program { public static void Main() { SomeValType[] a = new SomeValType[10]; a[0].m_x = 123; Console.WriteLine(a[0].m_x); // 显示 123 new FieldInitializationInCtor("Test"); TypeConstructorPerformance.Go(); ConversionOperator.Go(); ExtensionMethods.Go(); } } internal sealed class FieldInitializationInCtor //P(164) { // 不要显式初始化下面的字段 private Int32 x; private String s; private Double d; private Byte b; //该构造器将所有字段都设为默认值 //其他所有构造器都有显式调用该构造器 this 关键字 ,比上面的方法更加优雅 SetFieldDefaults(); public FieldInitializationInCtor() { x = 5; s = "Hi There!"; d = 3.14159; } // 这个构造器调用第一个默认构造器. public FieldInitializationInCtor(Int32 x) : this() { this.x = x; } // 这个构造器调用第一个默认构造器. public FieldInitializationInCtor(String s) : this() { this.s = s; } } public sealed class TypeConstructorPerformance { public static void Go() { //有构造器和没有构造器的性能分析 const Int32 iterations = 1000 * 1000 * 1000; PerfTest1(iterations); PerfTest2(iterations); } // 由于这个类没有显式定义类型构造器,所以C#在元数据中 // 用BeforeFieldInit来标记类型定义 internal sealed class BeforeFieldInit { public static Int32 s_x = 123; } // 由于这个类显式定义了类型构造器,所以C#在元数据中 // 没有用BeforeFieldInit来标记类型定义 internal sealed class Precise { public static Int32 s_x; static Precise() { s_x = 123; } } // 这个方法被JIT编译时, BeforeFieldInit 和Precise 类 // 的类型构造器还没有被执行,所以这些构造器的调用将嵌入 // 这个方法的代码中,使它允许较慢 private static void PerfTest1(Int32 iterations) { Stopwatch sw = Stopwatch.StartNew(); for (Int32 x = 0; x < iterations; x++) { // JIT编译器优化调用BeforeFieldInit 的 // 类型构造器的代码,是他在循环开始之前执行 BeforeFieldInit.s_x = 1; } Console.WriteLine("PerfTest1: {0} BeforeFieldInit", sw.Elapsed); sw = Stopwatch.StartNew(); for (Int32 x = 0; x < iterations; x++) { // JIT编译器在这里生成调用Precise 类的类型构造器的代码 // 所以每次循环迭代,它都要核实一遍是否需要调用构造器 Precise.s_x = 1; } Console.WriteLine("PerfTest1: {0} Precise", sw.Elapsed); } // 这个方法被JIT编译时, BeforeFieldInit 和Precise 类的 // 类型构造器已经执行过了。所以,在这个方法的代码中,不会 // 在对这些构造器的调用,是它运行得更快 private static void PerfTest2(Int32 iterations) { Stopwatch sw = Stopwatch.StartNew(); for (Int32 x = 0; x < iterations; x++) { BeforeFieldInit.s_x = 1; } Console.WriteLine("PerfTest2: {0} BeforeFieldInit", sw.Elapsed); sw = Stopwatch.StartNew(); for (Int32 x = 0; x < iterations; x++) { Precise.s_x = 1; } Console.WriteLine("PerfTest2: {0} Precise", sw.Elapsed); } } internal sealed class ConversionOperator { public static void Go() { Rational r1 = 5; // Int32 隐式转型Rational Rational r2 = 2.5f; // Single 隐式转型Rational Int32 x = (Int32)r1; // Rational 显式转化 Int32 Single s = (Single)r2; // Rational 显式转化 Single } public sealed class Rational //P(174) { //由一个int32构造一个Rational public Rational(Int32 num) { /* ... */ } // Single public Rational(Single num) { /* ... */ } // 将一个Rational 转化成一个Int32 public Int32 ToInt32() { /* ... */ return 0; } //将一个Rational 转化成 Single public Single ToSingle() { /* ... */ return 0f; } // 由一个Int32隐式构造并返回一个Rational public static implicit operator Rational(Int32 num) { // implicit 关键字告诉编译器是为了生产代码来调用方法,不需要在源码中进行显示转型。 // operator 关键字要跟随 implicit 或 explicit 之后, return new Rational(num); } // 由一个Single隐式构造并返回一个Rational public static implicit operator Rational(Single num) { // implicit 关键字告诉编译器是为了生产代码来调用方法,不需要在源码中进行显示转型。 return new Rational(num); } // 由一个Rational显式返回一个Int32 public static explicit operator Int32(Rational r) { // explicit 关键字告诉编译器是只有在发生显示转型时,才调用方法 return r.ToInt32(); } //由一个Rational显示范返回一个Single public static explicit operator Single(Rational r) { // explicit 关键字告诉编译器是只有在发生显示转型时,才调用方法 return r.ToSingle(); } } } #region 扩展方法 internal static class StringBuilderExtensions { public static Int32 IndexOf(this StringBuilder sb, Char value) { for (Int32 index = 0; index < sb.Length; index++) if (sb[index] == value) return index; return -1; } } internal static class ExtensionMethods { public static void Go()//P(177) { { var sb = new StringBuilder("Hello. My name is Jeff."); // 初始化字段 //将句点更改为感叹号,获取!字符索引(5) Int32 index = StringBuilderExtensions.IndexOf(sb.Replace('.', '!'), '!'); //首先,将句点更改为 sb.Replace('.', '!'); //接着,获取!字符的索引(5) index = StringBuilderExtensions.IndexOf(sb, '!'); // 将句点更改为感叹号,获取!字符索引(5) //ps 下面这样写法更为优雅。 index = sb.Replace('.', '!').IndexOf('!'); } {//P(179) // sb 是null StringBuilder sb = null; // 调用扩展方法:NullReferenceException 异常不会在调用IndexOf抛出 // 相反,NullReferenceException是在IndexOf内部的for循环抛出的 sb.IndexOf('X'); // 调用实例的方法。NullReferenceException 异常在调用Replace时抛出 sb.Replace('.', '!'); } SomeMethod(); } public static void SomeMethod()//P(180) { // 每个char 在控制台上显示一行 "Grant".ShowItems(); // 每个String 在控制台上单独显示一行 new[] { "Jeff", "Kristin" }.ShowItems(); // 每个Int32在控制台上单独显示一行 new List<Int32>() { 1, 2, 3 }.ShowItems(); // 创意一个Action的委托(实例)来应用静态ShowItems扩展方法, //并初始化第一个实参来引用字符串“Jeff” Action a = "Jeff".ShowItems; //调用(Invoke)委托,后者调用(call)showitems //并向它传递对字符串“Jeff”的引用 a(); } //定义委托的扩展方法 private static void ShowItems<T>(this IEnumerable<T> collection) { foreach (var item in collection) Console.WriteLine(item); Console.WriteLine(); } } #endregion /// <summary> /// 分部类演示,有的地方也叫部分类 /// </summary> internal static class PartialMethodsDemo { /// <summary> /// 没有应用分部方法的情况 /// </summary> private static class Inheritance //P(182) { // 工具生产的代码,存储在某个源码文件中: internal class Base { private String m_name; // 在更改m_name字段前调用 protected virtual void OnNameChanging(String value) { } public String Name { get { return m_name; } set { OnNameChanging(value.ToUpper()); // 告诉类要进行更改了 m_name = value; // 更改字段 } } } // 开发人员生产的代码,存储在另一个源代码文件中: internal class Derived : Base { protected override void OnNameChanging(string value) { if (String.IsNullOrEmpty(value)) throw new ArgumentNullException("value"); } } } /// <summary> /// 分部类的用法,对上面的代码进行优化改造。 /// </summary> internal static class PartialMethods { //工具生产的代码,存储在某个源码文件中: internal sealed partial class Base { private String m_name; // 这是分部方法的声明 partial void OnNameChanging(String value); public String Name { get { return m_name; } set { OnNameChanging(value.ToUpper()); // 通知类要进行更改了 m_name = value; // 更改字段 } } } // 开发人员生产的代码,存储在另一个源代码文件中: internal sealed partial class Base { #if false // Make 'true' to test the code with this method existing //这个是分部方法的实现,会在m_name更改前调用 partial void OnNameChanging(String value) { if (String.IsNullOrEmpty(value)) throw new ArgumentNullException("value"); } #endif } } public static void Go() { var inheritance = new Inheritance.Derived(); inheritance.Name = "Jeff"; var partialMethods = new PartialMethods.Base(); partialMethods.Name = "Jeff"; } }