第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";
}
}