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

 

posted @ 2019-01-09 09:45  eric.yuan  阅读(199)  评论(0编辑  收藏  举报