C# 构造函数入门






3.94/5 (138投票s)
2004 年 5 月 11 日
7分钟阅读

789798
这是一篇关于 C# 构造函数的文章,面向初学者。它涵盖了简单的构造函数、构造函数重载、继承中构造函数的行为、构造函数链以及静态构造函数。最后,它包含了关于构造函数的常见 FAQ。
引言
广义上讲,构造函数是类中在其对象创建时执行的方法。通常,我们将初始化代码放在构造函数中。在类中编写构造函数非常简单,看下面的示例
public class mySampleClass
{
public mySampleClass()
{
// This is the constructor method.
}
// rest of the class members goes here.
}
当此类的对象被实例化时,将执行此构造函数。类似这样
mySampleClass obj = new mySampleClass()
// At this time the code in the constructor will // be executed
构造函数重载
C# 支持构造函数的重载,这意味着我们可以 having 具有不同参数集的构造函数。因此,我们的类可以如下所示
public class mySampleClass
{
public mySampleClass()
{
// This is the no parameter constructor method.
// First Constructor
}
public mySampleClass(int Age)
{
// This is the constructor with one parameter.
// Second Constructor
}
public mySampleClass(int Age, string Name)
{
// This is the constructor with two parameters.
// Third Constructor
}
// rest of the class members goes here.
}
好的,请注意,对构造函数的调用现在取决于您实例化对象的方式。例如
mySampleClass obj = new mySampleClass()
// At this time the code of no parameter
// constructor (First Constructor)will be executed
mySampleClass obj = new mySampleClass(12)
// At this time the code of one parameter
// constructor(Second Constructor)will be
// executed.
对构造函数的调用完全受重载规则的约束。
从另一个构造函数调用构造函数
您始终可以在一个构造函数内部调用另一个构造函数。例如
public class mySampleClass
{
public mySampleClass(): this(10)
{
// This is the no parameter constructor method.
// First Constructor
}
public mySampleClass(int Age)
{
// This is the constructor with one parameter.
// Second Constructor
}
}
首先,让我们看看这个语法是什么
public mySampleClass(): this(10)
在这里,this
指的是同一个类,所以当我们说 this(10)
时,我们实际上是指执行 public mySampleClass(int Age)
方法。上面调用方法的方式称为初始化程序。我们最多可以在方法中使用一个这样的初始化程序。
我们还必须了解执行顺序,即哪个方法何时执行。在这里,如果我这样实例化对象
mySampleClass obj = new mySampleClass()
那么 public mySampleClass(int Age)
的代码将在 mySampleClass()
的代码之前执行。所以,实际上该方法的定义
public mySampleClass(): this(10)
{
// This is the no parameter constructor method.
// First Constructor
}
等同于
public mySampleClass()
{
mySampleClass(10)
// This is the no parameter constructor method.
// First Constructor
}
注意:上面的代码(就在这行代码的上方)仅为类比提及,不会编译。目的是说明如果使用初始化程序,执行流程。
我们不能像处理简单方法一样显式调用 C# 中的构造函数,例如:上面代码中的语句 mySampleClass(10)
将不起作用。您只能通过初始化程序从一个构造函数调用另一个构造函数。
对于 VB.NET 程序员:您可以通过语法 Me.New(param list)
调用同一类的另一个构造函数,但它应该是调用构造函数方法的第一行。因此,最终,被调用构造函数中的代码将在调用构造函数中的代码之前运行,这在这里与初始化程序相同。
请注意,在初始化程序中只允许使用 this
和 base
(稍后会介绍)关键字,其他方法调用将引发错误。
这有时被称为构造函数链。
呼……简单的事情变得困难,但就是这样。无论如何,让我们继续。
继承中构造函数的行为
首先,让我们创建派生类。
public class myBaseClass
{
public myBaseClass()
{
// Code for First Base class Constructor
}
public myBaseClass(int Age)
{
// Code for Second Base class Constructor
}
// Other class members goes here
}
public class myDerivedClass : myBaseClass
// Note that I am inheriting the class here.
{
public myDerivedClass()
{
// Code for the First myDerivedClass Constructor.
}
public myDerivedClass(int Age):base(Age)
{
// Code for the Second myDerivedClass Constructor.
}
// Other class members goes here
}
现在,这里的执行顺序是什么
如果我这样创建派生类的对象
myDerivedClass obj = new myDerivedClass()
那么执行顺序将是
public myBaseClass()
方法。- 然后是
public myDerivedClass()
方法。
注意:如果我们没有提供引用基类构造函数的初始化程序,它将执行基类的无参数构造函数。
请注意一点:我们既没有通过初始化程序也没有通过 base
关键字显式调用基类的构造函数,但它仍然在执行。这是构造函数的正常行为。
如果我这样创建派生类的对象
myDerivedClass obj = new myDerivedClass(15)
那么执行顺序将是
public myBaseClass(int Age)
方法- 然后是
public myDerivedClass(int Age)
方法
在这里,新的关键字 base
出现了。它引用当前类的基类。所以,这里它指的是 myBaseClass
。而 base(10)
指的是调用 myBaseClass(int Age)
方法。
另请注意 Age
变量在语法中的用法:public myDerivedClass(int Age):base(Age)
。 [理解它留给读者]。
私有构造函数
私有构造函数,即带有“private
”访问修饰符的构造函数,是一个特殊的案例。因为我们既不能创建类的对象,也不能仅通过 private
构造函数来继承类。但是,是的,我们可以在类中拥有 public
构造函数集以及 private
构造函数,并且 public
构造函数可以通过构造函数链从类内部访问 private
构造函数。
例如,我的类是这样的
public class myClass
{
private MyClass()
{
Console.WriteLine("This is no parameter Constructor");
}
public MyClass(int var):this()
{
Console.WriteLine("This is one parameter Constructor");
}
// Other class methods goes here
}
然后我们可以通过以下语句创建这个类的对象
MyClass obj = new MyClass(10);
上面的语句将正常工作,但是下面的语句
MyClass obj = new MyClass();
将引发错误:'Constructors.MyClass.MyClass()' is inaccessible due to its protection level
可以拥有只有私有构造函数的类。但是是的,如我所说,这样的类既不能实例化也不能继承。如果我们尝试继承一个只有私有构造函数的类,我们将得到与上面相同的错误。还请记住,一旦您自己提供了构造函数,编译器就不会为您的类添加无参数的公共构造函数。
好吧,这类类的一个使用场景可能是——当类中只有静态成员而不需要实例化它时。
呼……迷失了……构造函数还有什么没讲的吗?是的,静态构造函数。哈!!那么,它们是什么?让我们看看……
静态构造函数
这是 C# 中引入的新概念。所谓新,我是指它在 C++ 程序员中不可用。这是一个特殊的构造函数,在类的第一个对象创建之前被调用。执行时间无法确定,但肯定是在第一个对象创建之前——可能是在加载程序集的时。
编写静态构造函数的语法也非常简单。这是
public class myClass
{
static myClass()
{
// Initialization code goes here.
// Can only access static members here.
}
// Other class methods goes here
}
静态构造函数的注意事项
- 类中只能有一个静态构造函数。
- 静态构造函数应不带参数。
- 它只能访问类的静态成员。
- 静态构造函数定义中不应包含访问修饰符。
好的,以上所有几点都还可以,但为什么会这样呢?让我们一步一步来。
首先,静态方法的调用是由 CLR 制作的,而不是由对象制作的,所以我们不需要为它设置访问修饰符。
其次,它将由 CLR 调用,CLR 可以根据需要向其传递参数。所以我们不能有带参数的静态构造函数。
第三,类中的非静态成员是实例特定的。所以静态构造函数,如果允许操作非静态成员,将反映在所有实例对象中,这是不切实际的。所以静态构造函数只能访问类的静态成员。
第四,重载需要两个方法在方法定义方面有所不同,而这对于静态构造函数来说是做不到的,所以你最多只能有一个静态构造函数。
现在,这里有一个问题,我们可以有两个构造函数,比如
public class myClass
{
static myClass()
{
// Initialization code goes here.
// Can only access static members here.
}
public myClass()
{
// Code for the First myDerivedClass Constructor.
}
// Other class methods goes here
}
这是完全有效的,尽管似乎不符合重载概念。但为什么?因为两个方法的执行时间是不同的。一个是程序集加载时,一个是对象创建时。
构造函数 FAQ
- 类必须有构造函数吗?
是的,类必须有构造函数,而且该构造函数必须对对象可访问,即它应该具有正确的访问修饰符。例如,如果我们类中只有私有构造函数,而我们有兴趣实例化该类,即想创建类的对象,那么只有私有构造函数是不够的,事实上它会引发错误。所以,应该为构造函数提供正确的访问修改符。
- 如果我不写构造函数怎么办?
在这种情况下,编译器将在后台尝试为您的类提供无参数构造函数。编译器只有在您没有为类编写构造函数时才会尝试此操作。如果您提供任何构造函数(带或不带参数),编译器将不会进行此类尝试。
- 如果我有一个构造函数
public myDerivedClass()
,但没有public myBaseClass()
怎么办?这将引发错误。如果无参数构造函数缺失或不可访问(例如它是
private
),它将引发错误。您需要在此处采取预防措施。 - 我们可以从非静态(普通)构造函数访问静态成员吗?
是的,我们可以。对非静态构造函数没有这样的限制。但是静态构造函数有一个限制,即它只能访问静态成员。