zoukankan      html  css  js  c++  java
  • C#基础 [10] 构造函数

    一、构造函数概述

       构造函数是在创建给定类型的对象时执行的类方法。构造函数具有与类相同的名称,它是类或结构中第一个被执行的方法,通常用于申请内存、初始化新对象的数据成员。任何时候,只要创建类或结构,就会调用它的构造函数。构造函数可以重载,即类或结构可能有多个接受不同参数的构造函数。构造函数使得程序员可设置默认值、限制实例化以及编写灵活且便于阅读的代码。构造函数也被称为构造器或构造方法。

    二、实例构造函数

      1.默认构造函数

         如果在类声明中没有显式声明构造函数,那么编译器会自动生成一个隐式的默认构造函数。该构造函数的函数名和类名相同、public、没有参数、方法体为空,它实例化对象,并且将成员字段初始化为成员类型的默认值。无论何时,只要使用 new 运算符实例化对象,并且不为 new 提供任何参数,就会调用默认构造函数。下面是一个Person类的声明,没有显式声明构造函数。

    View Code
     1  // 无显式构造函数   
     2  class Person
     3     {
     4         // Fields       
     5         private string _name;      
     6 
     7         // Methods
     8         /// <summary>
     9         /// 设置新名称
    10         /// </summary>
    11         /// <param name="newName"></param>
    12         public void SetName(string newName)
    13         {
    14             this.Name = newName;
    15         }
    16 
    17         // Properties
    18         public string Name
    19         {
    20             get { return _name; }
    21             set { _name = value; }
    22         }
    23     }

        下面是编译器为Person类自动生成的默认构造函数:  

    1 public Person()
    2 {
    3 }

        下面是使用new运算符创建类的实例,它调用了默认的无参构造函数。

    1     class Program
    2     {
    3         static void Main(string[] args)
    4         {
    5             // 调用默认构造函数创建类对象
    6             var p = new Person();
    7         }
    8     }

     2.显式声明的无参构造函数

        显式声明的无参构造函数有如下特征:

        第一,构造函数名和类名相同,可以有修饰符。

        第二,构造函数无返回值,连void都没有。

        第三,可以带有访问修饰符,如果允许从类的外部创建类的实例,则为public。 

        下面是一个为上面的Person类显示声明的一个public无参构造函数,它为成员字段Name和isInitialized设了初始值:

    1         // Constructor
    2         public Person()
    3         {
    4             this.Name = "unknow";
    5             this.isInitialized = true;
    6         }

       第四,一旦为类显式声明了任何一个构造函数,编译器就不会为该类生成默认的构造函数,这时如果还想调用和默认构造函数一样的无参构造函数,就必须得显式声明,否则编译器会报错。下面为Person类的构造函数加上参数,使得与默认构造函数相同的声明不存在了:

    1         // Constructor
    2         // 为构造函数声明一个参数,与默认构造函数相同的声明不存在了
    3         public Person(string name)
    4         {
    5             this.Name = name;
    6             this.isInitialized = true;
    7         }

      然后,调用默认构造函数实例化一个对象就会报错:

                // 调用默认构造函数创建类对象
                var p = new Person();          

      3.构造函数的参数与重载

        构造函数与其他方法一样,可以带有参数,也可以重载。这样就可以根据条件传递不同的参数,实例化对象了。下面为Person类添加了一个Age属性和两个构造函数的重载:

    View Code
     1     class Person
     2     {
     3         // Fields       
     4         private string _name;
     5         private int _age;
     6 
     7         public bool isInitialized;
     8 
     9         // Constructor
    10         // 1.与默认构造函数一致的无参构造函数
    11         public Person()
    12         {
    13 
    14         }
    15         // 2.为构造函数声明一个参数,与默认构造函数相同的声明不存在了
    16         public Person(string name)
    17         {
    18             this.Name = name;
    19             this.isInitialized = true;
    20         }
    21         // 3.构造函数的重载2,有两个参数
    22         public Person(string name, int age)
    23         {
    24             this.Name = name;
    25             this.Age = age;
    26         }
    27 
    28         // Methods
    29         /// <summary>
    30         /// 设置新名称
    31         /// </summary>
    32         /// <param name="newName"></param>
    33         public void SetName(string newName)
    34         {
    35             this.Name = newName;
    36         }
    37 
    38         // Properties
    39         public string Name
    40         {
    41             get { return _name; }
    42             set { _name = value; }
    43         }
    44         public int Age
    45         {
    46             get { return _age; }
    47             set { _age = value; }
    48         }
    49     }

        下面分别调用各个构造函数实例化对象:

    View Code
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             // 1.调用默认构造函数创建类对象
     6             var p = new Person();           
     7 
     8             // 2.调用一个参数的构造函数创建对象
     9             var p1 = new Person("李白");
    10 
    11             // 3.调用两个参数的构造函数创建对象
    12             var p2 = new Person("李白", 18);
    13         }
    14     }

    三、静态构造函数

      静态构造函数用于初始化任何 静态数据,或用于执行仅需执行一次的特定操作。在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。下面为Person类添加了一个static字段和一个static构造函数:

    View Code
     1     class Person
     2     {
     3         // Fields       
     4         private string _name;
     5         private int _age;
     6         // 静态字段
     7         private static string _test;
     8 
     9         public bool isInitialized;
    10 
    11         // Constructor
    12         // 1.与默认构造函数一致的无参构造函数
    13         public Person()
    14         {
    15 
    16         }
    17         // 2.为构造函数声明一个参数,与默认构造函数相同的声明不存在了
    18         public Person(string name)
    19         {
    20             this.Name = name;
    21             this.isInitialized = true;
    22         }
    23         // 3.构造函数的重载2,有两个参数
    24         public Person(string name, int age)
    25         {
    26             this.Name = name;
    27             this.Age = age;
    28         }
    29 
    30         // 静态构造函数
    31         static Person()
    32         {
    33             _test = "test static constructor";
    34             Console.WriteLine("我是静态构造函数,我被调用!");
    35         }
    36 
    37         // Methods
    38         /// <summary>
    39         /// 设置新名称
    40         /// </summary>
    41         /// <param name="newName"></param>
    42         public void SetName(string newName)
    43         {
    44             this.Name = newName;
    45         }
    46 
    47         // Properties
    48         public string Name
    49         {
    50             get { return _name; }
    51             set { _name = value; }
    52         }
    53         public int Age
    54         {
    55             get { return _age; }
    56             set { _age = value; }
    57         }
    58     }

      静态构造函数有如下特征:

      第一,静态构造函数既没有访问修饰符,也没有参数。试图为静态构造函数添加修饰符将得到一条如下图所示的错误消息:

      

      第二, 在程序中,用户无法直接调用静态构造函数;用户无法控制何时执行静态构造函数;在创建第一个实例或引用任何静态成员之前,系统将自动调用静态构造函数来初始化类。试图手动调用构造函数,根本找不到:

      

      第三,即使创建类的多个实例,静态构造函数也仅运行一次,并且在实例构造函数运行之前运行。下面调用构造函数的不同重载版本创建3个Person类的实例:

    View Code
     1         static void Main(string[] args)
     2         {
     3             // 1.调用默认构造函数创建类对象
     4             var p = new Person();
     5             p.Name = "test";
     6             Console.WriteLine(p.Name);
     7 
     8             // 2.调用一个参数的构造函数创建对象
     9             var p1 = new Person("李白");
    10             Console.WriteLine(p1.Name);
    11 
    12             // 3.调用两个参数的构造函数创建对象
    13             var p2 = new Person("李白", 18);
    14             Console.WriteLine("姓名:{0},年龄{1}", p2.Name, p2.Age);
    15             Console.ReadKey();
    16         }

      下图是上面调用代码的执行结果,结果表明创建3个类实例,static构造函数是由系统自动调用,并且仅仅调用了一次:

      

      第四,静态构造函数的典型用途是:当类使用日志文件时,将使用这种构造函数向日志文件中写入项。静态构造函数在为非托管代码创建包装类时也很有用,此时该构造函数可以调用 LoadLibrary 方法。

      第五,如果静态构造函数引发异常,运行时将不会再次调用该构造函数,并且在程序运行所在的应用程序域的生存期内,类型将保持未初始化。

    四、私有构造函数

       私有构造函数是一种特殊的实例构造函数。它通常用在只包含静态成员的类中。如果类具有一个或多个私有构造函数而没有公共构造函数,则其他类(除嵌套类外)无法创建该类的实例。例如,下面的示例声明了一个名为NLog的类,它只有一个private构造函数和一个静态方法。无法在外部实例化该类,只能访问它的静态成员方法:

    View Code
     1     class MyLog
     2     {
     3         // 私有构造函数
     4         private MyLog()
     5         {
     6 
     7         }
     8 
     9        public static void SLog()
    10         {
    11             Console.WriteLine("我是一个静态成员方法!");
    12 
    13         }
    14     }
    15     class Program
    16     {
    17         static void Main(string[] args)
    18         {
    19             // 无公开的构造函数,法实例化
    20             MyLog myLog = new MyLog();
    21 
    22             // 只能访问静态成员
    23             MyLog.SLog();
    24 
    25         }
    26     }

      注意,如果您不对构造函数使用访问修饰符,则在默认情况下它仍为私有构造函数。但是,通常显式地使用 private 修饰符来清楚地表明该类不能被实例化。

    五、复制构造函数

      如果我们创建了类的一个新的对象并希望从现有对象复制值,那么我们可以声明一个专门用于复制值的构造函数。例如,下面的实例中 Person 类包含一个构造函数,该构造函数接受另一个 Person 类型的对象作为其参数。然后此对象的字段中的内容将分配给新对象中的字段。备用复制构造函数将要复制的对象的 name 和 age 字段发送到类的实例构造函数。

    View Code
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             // 实例化一个Person类的对象
     6             Person person1 = new Person("George", 40);
     7 
     8             // 采用对象person1的值实例化另一个Person类的对象
     9             Person person2 = new Person(person1);
    10             Console.WriteLine(person2.Details);
    11           
    12             Console.ReadKey();
    13         }
    14     }
    15 
    16     class Person
    17     {
    18         private string name;
    19         private int age;
    20 
    21         // 复制构造函数
    22         public Person(Person previousPerson)
    23         {
    24             name = previousPerson.name;
    25             age = previousPerson.age;
    26         }
    27                
    28         // 实例构造函数
    29         public Person(string name, int age)
    30         {
    31             this.name = name;
    32             this.age = age;
    33         }
    34 
    35         // Get 访问器
    36         public string Details
    37         {
    38             get
    39             {
    40                 return name + " is " + age.ToString();
    41             }
    42         }
    43     }   

      参考:http://msdn.microsoft.com/zh-cn/library/ms173116(VS.100).aspx

    六、对象初始化器

       一般我们创建对象都是使用对象创建表达式:即“new运算符+类的构造函数”。通过这种方式创建完对象之后,再为对象的属性赋值,很麻烦。有一个对象创建表达式的升级版本,它可以简化对象的创建和初始值设定的过程:就是用对象初始化器。对象初始化器有称为“对象初始值设定项”或“对象初始化列表”,用于在创建对象的表达式中为对象的成员赋初值。下面是使用对象初始化器创建对象的两种方式:

    1             // 对象初始化器1:包含参数列表
    2             var person1 = new Person("哈哈") { Name = "哈哈" };
    3 
    4             // 对象初始化器2:省略参数列表(推荐)
    5             var person2 = new Person { Name = "汤姆", Age = 18 };

      第二种方式推荐使用,因为它更加简洁,参数列表也是没有必要的。此外,推荐使用var关键字代替类型名。  

      参考:http://msdn.microsoft.com/zh-cn/library/ace5hbzh(VS.100).aspx

  • 相关阅读:
    DMN 决策逻辑与决策依赖之间的联系
    DMN 决策依赖DRG和DRD
    DMN 决策模型标记 介绍
    DMN 决策模型和标记 Decision Model And Notation
    RuleML 例子
    RuleML 例子
    RuleML 例子
    RuleML入门(下)
    RuleML 入门(上)
    osg 线框模式,点模式切换
  • 原文地址:https://www.cnblogs.com/sunyunh/p/2842015.html
Copyright © 2011-2022 走看看