第十六章 代码组织与管理

  本章介绍C#语言所特有的一些代码特性,包括用于源代码分散管理的分布类型(Partial Type)、用于代码编译管理的预处理器指令,以及支持软件文档生成的XML代码注释。

1 分布类型

  有时候在一个类的定义中可能包含大量的字段和方法成员,甚至大量的嵌套类型,导致代码行数太多,管理起来很不方便。为此,C#中提供了分布类型概念,允许将一个类的定义分散到多个代码片段之中,而这些代码片段又可以放在不同的源文件中。采用这种方式定义的类叫做分布类。分布类型同样适用于结构和接口,所定义的类型分别叫做分布结构和分布接口。

1.1 分布类型的定义

  分布类型通过修饰符partial进行定义,该修饰符可以出现在关键字class、struct和interface之前,用于定义不同的分布类型,例如:

public partial interface IOutput{}
public partial class Contact{}
public partial struct Table{}

  由于类的名称相同,下面两段代码共同组成了一个分布类Contact的定义:

public partial class Contact
{
    private string m_name;
}

public partial class Contact
{
    private string m_gender;
}

  一旦某个类型被定义为分布类型,那么在其每一部分的定义中都必须使用partial修饰符。这些部分可以在不同的源文件中,但有以下要求:

  • 各部分使用的访问限制修饰符应当相同;

  • 各部分不能包含重复的成员的定义,除非该成员属于嵌套的分布类型;

  • 各部分不能定义不同的基类

  • 它们所在的命名空间的名称必须相同,否则就是分属于不同的程序集的不同类型;

  • 它们所分布的各个源文件必须在一起编译。

  和访问限制修饰符不同,只要在分布类型的任何部分的定义中使用了abstract或sealed修饰符(注意这两个修饰符不能同时出现),那么该类型就是抽象类型或密封类型。

  不允许在分布类型的不同部分定义不同的基类。但对于接口则没有这个限制,所有部有继承的接口(可以重复出现)共同组成了整个分布类型继承的接口。

  可以将嵌套类型也定义为分布的,这时有两种情况:

  一是嵌套类型所在的外部类型不是分布类型,那么其各部分定义就必须全部在外部类型的当前定义中,例如:

public class Contact
{
    public partial class ChangeEventArgs : EventArgs
    {
        ...
    }
    
    public partial class ChangeEventArgs
    {
        ...
    }
}

  二是嵌套类型所在的外部类型也是分布类型,那么其各部分定义也可以分布在外部类型的不同部分当中,其它要求和一般的分布类型相同,例如:

public partial class Contact
{
    ...
    public partial class ChangeEventArgs : EventArgs
    {
        ...
    }
}

public partial class Contact
{
    ...
    public partial class ChangeEventArgs
    {
        ...
    }
}

1.2 分布泛型

  泛型类型采用分布类型的定义方式,必须满足对一般分布类型的定义要求。由于泛型的特殊性,分布的泛型在类型参数的使用上还有下列附加规则:

   • 泛型的类型参数在每个部分都需要进行声明,而且数量和名称必须完全相同;

   • 如果在部分定义中出现了类型限制,这就是对整个泛型的类型限制;

   • 如果多个部分定义中都现出了类型限制,那么这些限制必须相同(包括继承限制和构造函数限制),但对书写的次序没有要求;

2 代码中的预处理器指令

2.1 条件编译

  先看下面的程序:

#define Detail
using System;

namespace P18_5
{
    class PreprocessSample
    {
        static void Main()
        {
            Console.WriteLine("请输入1~50之间的一个整数:");
            int n;
            while (!int.TryParse(Console.ReadLine(), out n) || n < 1 || n > 50)
            {
                Console.WriteLine("请输入1~50之间的一个整数:");
            }
            if (n == 1)
            {
                Console.WriteLine("FB(1) = 1");
                return;
            }
            long l1 = 1, l2 = 2, lTmp;
#if(Detail)
            {
            for (int i = 1; i < n - 1; i++)
            {
                lTmp = 12;
                l2 = l2 + l1;
                Console.WriteLine("FB({0}) = {1} + {2} = {3}", i + 2, l1, lTmp, l2);
                l1 = lTmp;
            }
            }
#else
            {
            for (int i = 1; i < n - 1; i++)
            {
                lTmp = 12;
                l2 = l2 + l1;
                l1 = lTmp;
            }
            }
#endif
            Console.WriteLine("运算结果:FB({0})= {1}", n, l2);
        }
    }
}

   运行结果为:

请输入1~50之间的一个整数:
30
FB(3) = 1 + 12 = 3
FB(4) = 12 + 12 = 15
FB(5) = 12 + 12 = 27
FB(6) = 12 + 12 = 39
FB(7) = 12 + 12 = 51
FB(8) = 12 + 12 = 63
FB(9) = 12 + 12 = 75
FB(10) = 12 + 12 = 87
FB(11) = 12 + 12 = 99
FB(12) = 12 + 12 = 111
FB(13) = 12 + 12 = 123
FB(14) = 12 + 12 = 135
FB(15) = 12 + 12 = 147
FB(16) = 12 + 12 = 159
FB(17) = 12 + 12 = 171
FB(18) = 12 + 12 = 183
FB(19) = 12 + 12 = 195
FB(20) = 12 + 12 = 207
FB(21) = 12 + 12 = 219
FB(22) = 12 + 12 = 231
FB(23) = 12 + 12 = 243
FB(24) = 12 + 12 = 255
FB(25) = 12 + 12 = 267
FB(26) = 12 + 12 = 279
FB(27) = 12 + 12 = 291
FB(28) = 12 + 12 = 303
FB(29) = 12 + 12 = 315
FB(30) = 12 + 12 = 327
运算结果:FB(30)= 327
请按任意键继续. . .

  注意程序的第一行代码:

#define Detail

  这是一个预处理指令,它为程序定义了一个名为Detail的标识符。而程序主方法中出现的#if-#else-#endif语句是一个条件编译语句,它根据程序是否存在标识符Detail来选择要编译的代码。如果把程序第一行的预处理器指令去掉,输出结果为:

请输入1~50之间的一个整数:
30
运算结果:FB(30)= 327
请按任意键继续. . .

2.1.1 #define和#undef指令

  它们叫做标识符定义指令,分别用于定义和取消标识符,使用时后跟标识符的名称。#define和#undef必须出现在所有代码之前(不包括注释)。例如,可以在程序P18_5.CS中再插入一条#undef指令,这样就取消了#define指令结标识符Detail的定义,程序将不显示详细的计算过程:

#define Detail
#undef Detail

  标识符只是一个编译符号,和变量没有变量。在程序中可以定义一个变量Detail,并不会和标识符Detail产生命名冲突。

2.1.2 #if、#else、#elif和#endif指令

  它们都叫做条件编译指令。在使用时,#if和#elif指令后跟标识符表达式。标识符表达式可以是单个标识符,还可以是通过与操作符“&&”以及或操作符“||”进行连接的多个标识符。

  条件编译指令可以组成3种结构

  (1)#if-#endif结构

  (2)#if-#else-#endif结构

  (3)#if-#elif-#else-#endif结构

2.2 编译警告和错误

2.2.1 #warning指令

  当所在代码被编译时,#warning指令生成一条警告信息。它使用时后跟要输出的警告内容。使用C#编译器时,可以通地编译选项“/nowarn”来关闭警告信息的显示.

  例如,下面的程序在编译时会生成警告信息“正在使用控制台应用程序”:

class PreprocessSample
{
    static void Main()
    {
#warning 正在使用控制台应用程序
        //
    }
}

2.2.2 #error指令

  当所在的代码被编译时,#error指令生成一条错误信息。它使用时后跟要输出的错误内容。与#warning指令不同的是,#error指令的执行会导致编译的失败。

2.2.3 其它预处理指令

  • #region和#endregion,二者配套使用,支持代码区域的折叠和展开。

  • #line指令,用于指定代码所在的行数

  • #pragma指令,要求编译器使用指定的指令来编译源程序

  • #pragma warning指令,用于在编译时打或关闭指定的警告信息。

3 XML代码注释

  如果程序中的代码注释符合特定的XML语法规则,那么在将代码编译成程序的同时,还能够根据这些注释内容生成对应的XML软件文档。

3.1 XML简介

  XML的中文译法叫做可扩展标记语言(eXtensible Markup Language),是一个格式独立的,与平台和应用无关的语言。

3.2 使用XML注释

        /// <summary>
        /// 主方法
        /// </summary>
        static void Main(){}
原文地址:https://www.cnblogs.com/boywg/p/4149980.html