100165817.htm
来自「C#高级编程(第三版),顶死你们。。 。up」· HTM 代码 · 共 292 行 · 第 1/5 页
HTM
292 行
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> name = "<no name>";</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">如果编译器没有在起始花括号的前面找到对另一个构造函数的任何引用,它就会假定我们要调用基类构造函数——这符合前面介绍的默认构造函数的工作方式。</span></p>
<p class="MsoNormal"><span lang="EN-US">base </span><span style="FONT-FAMILY: 宋体">和</span><span lang="EN-US"> this</span><span style="FONT-FAMILY: 宋体">关键字是调用另一个构造函数时允许使用的惟一关键字,其他关键字都会产生编译错误。还要注意只能指定一个其他的构造函数。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">到目前为止,这段代码运行正常。但是,要通过构造函数的层次结构把级数弄乱的最好方法是把构造函数声明为私有函数:</span></p>
<p class="2" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> private GenericCustomer()</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> name = "<no name>";</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">如果试图这样做,就会产生一个有趣的编译错误,如果不理解构造是如何按照层次结构由上而下的顺序工作的,这个错误会让人摸不着头脑。</span></p>
<p class="a6" style="MARGIN: 8.15pt 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">'Wrox.ProCSharp.GenericCustomer()' is inaccessible due to its protection level</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">有趣的是,该错误没有发生在</span><span lang="EN-US">GenericCustomer</span><span style="FONT-FAMILY: 宋体">类中,而是发生在派生类</span><span lang="EN-US">Nevermore60Customer</span><span style="FONT-FAMILY: 宋体">中。编译器试图为</span><span lang="EN-US">Nevermore60Customer</span><span style="FONT-FAMILY: 宋体">生成默认的构造函数,但又做不到,因为默认的构造函数应调用无参数的</span><span lang="EN-US">GenericCustomer</span><span style="FONT-FAMILY: 宋体">构造函数。把该构造函数声明为</span><span lang="EN-US">private</span><span style="FONT-FAMILY: 宋体">,它就不可能访问派生类了。如果为带有参数的</span><span lang="EN-US">GenericCustomer</span><span style="FONT-FAMILY: 宋体">提供一个构造函数,但没有提供无参数的构造函数,也会发生类似的错误。在本例中,编译器不能为</span><span lang="EN-US">GenericCustomer</span><span style="FONT-FAMILY: 宋体">生成默认构造函数,所以当编译器试图为派生类生成默认构造函数时,编译器会再次发现它不能做到这一点,因为对于派生类来说,没有无参数的基类构造函数可调用。这个问题的解决方法是为派生类添加自己的构造函数<span style="LETTER-SPACING: -1pt">——</span></span><span style="LETTER-SPACING: -1pt"> </span><span style="FONT-FAMILY: 宋体">实际上不需要在这些构造函数中做任何工作,这样,编译器就不会为这些派生类生成默认构造函数了。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">前面介绍了所有的理论知识,下面用一个例子来说明如何给类的层次结构添加构造函数。下一节为</span><span lang="EN-US">MortimerPhones</span><span style="FONT-FAMILY: 宋体">样例添加带参数的构造函数。</span></p>
<h4 style="TEXT-INDENT: 21.45pt"><span lang="EN-US">2. </span><span style="FONT-FAMILY: 黑体">在层次结构中添加带有参数的构造函数</span></h4>
<p class="MsoNormal"><span><span style="FONT-FAMILY: 宋体">首先是带一个参数的</span><span lang="EN-US">MortimerPhones</span></span><span style="FONT-FAMILY: 宋体">构造函数,它仅在顾客提供其姓名时才实例化顾客:</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> abstract class GenericCustomer</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> private string name;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> public GenericCustomer(string name)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> this.name = name;</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">到目前为止,代码运行一切正常,但刚才说过,在编译器试图为派生类创建一个默认构造函数时,会产生一个编译错误,因为编译器为</span><span lang="EN-US">Nevermore60Customer</span><span style="FONT-FAMILY: 宋体">生成的默认构造函数会试图调用无参数的</span><span lang="EN-US">GenericCustomer</span><span style="FONT-FAMILY: 宋体">构造函数,但</span><span lang="EN-US">GenericCustomer</span><span style="FONT-FAMILY: 宋体">没有这样的构造函数。因此,需要为派生类提供一个构造函数,来避免这个错误:</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span><span lang="EN-US">class Nevermore60Customer : GenericCustomer</span></span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">{</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> private uint highCostMinutesUsed;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> public Nevermore60Customer(string name)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> : base(name)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">现在,</span><span lang="EN-US">Nevermore60Customer</span><span style="FONT-FAMILY: 宋体">对象的实例只能在提供了包含顾客姓名的字符串后创建,这正是我们需要的。有趣的是</span><span lang="EN-US">Nevermore60Customer</span><span style="FONT-FAMILY: 宋体">构造函数对这个字符串所做的处理。它本身不能初始化</span><span lang="EN-US">name</span><span style="FONT-FAMILY: 宋体">字段,因为它不能访问基类中的私有字段,但可以把顾客姓名传送给基类,以便</span><span lang="EN-US">GenericCustomer</span><span style="FONT-FAMILY: 宋体">构造函数处理。具体方法是,把先执行的基类构造函数指定为把顾客姓名当做参数的构造函数。除此之外,它不需要执行任何操作。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">下面讨论如果要处理不同的重载构造函数和一个类的层次结构,会发生什么情况。假定</span><span lang="EN-US">Nevermore60Customers</span><span style="FONT-FAMILY: 宋体">通过朋友联系到</span><span lang="EN-US">MortimerPhones</span><span style="FONT-FAMILY: 宋体">,即</span><span lang="EN-US">MortimerPhones</span><span style="FONT-FAMILY: 宋体">公司中有一个人是朋友,因此可以获得折扣。这表示在构造一个</span><span lang="EN-US">Nevermore60Customer</span><span style="FONT-FAMILY: 宋体">时,还需要传递联系人的姓名。在现实生活中,构造函数必须利用该姓名去完成更复杂的工作,例如处理折扣等,但这里只是把联系人的姓名存储到另一个字段中。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">此时,</span><span lang="EN-US">Nevermore60Customer</span><span style="FONT-FAMILY: 宋体">定义如下所示:</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span><span lang="EN-US"> class Nevermore60Customer : GenericCustomer</span></span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> { </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> public Nevermore60Customer(string name, string referrerName)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> : base(name) </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> { </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> this.referrerName = referrerName;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> }</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> private string referrerName;</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> private uint highCostMinutesUsed;</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">该构造函数将姓名作为参数,并把它传递给</span><span lang="EN-US">GenericCustomer</span><span style="FONT-FAMILY: 宋体">构造函数进行处理。</span><span lang="EN-US">ReferrerName</span><span style="FONT-FAMILY: 宋体">是一个变量,我们需要声明它,这样构造函数才能在其主体中处理这个参数。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">但是,并不是所有的</span><span lang="EN-US">Nevermore60Customers</span><span style="FONT-FAMILY: 宋体">都有联系人,所以还需要有一个不需此参数的构造函数</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">或者说是为它提供默认值的构造函数</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">。实际上,我们指定如果没有联系人,</span><span lang="EN-US">ReferrerName</span><span style="FONT-FAMILY: 宋体">字段就设置为</span><span lang="EN-US"><None></span><span style="FONT-FAMILY: 宋体">。下面是这个带有一个参数的构造函数:</span></p>
<p class="2" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> <span>public Nevermore60Customer(string name)</span></span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span><span lang="EN-US"> : this(name, "<None>")</span></span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> {</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> } </span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">这样就正确建立了所有的构造函数。执行下面的代码时,检查事件链是很有益的:</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 8.15pt 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> GenericCustomer customer = new Nevermore60Customer("Arabel Jones");</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">编译器认为它需要带有一个字符串参数的构造函数,所以它确认的构造函数就是刚才定义的那个构造函数,如下所示。</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> public Nevermore60Customer(string Name)</span></p>
<p class="a6" style="BACKGROUND: #f2f2f2; MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> : this(Name, "<None>")</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">在实例化</span><span lang="EN-US">customer</span><span style="FONT-FAMILY: 宋体">时,就会调用这个构造函数。之后立即把控制权传送给对应的</span><span lang="EN-US">Nevermore60Customer</span><span style="FONT-FAMILY: 宋体">构造函数,该构造函数带有</span><span lang="EN-US">2</span><span style="FONT-FAMILY: 宋体">个参数,分别是</span><span lang="EN-US">Arabel Jones</span><span style="FONT-FAMILY: 宋体">和</span><span lang="EN-US"><None></span><span style="FONT-FAMILY: 宋体">。在这个构造函数中,把控制权依次传送给</span><span lang="EN-US">GenericCustomer</span><span style="FONT-FAMILY: 宋体">构造函数,该构造函数带有</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体">个参数,即字符串</span><span lang="EN-US">Arabel Jones</span><span style="FONT-FAMILY: 宋体">。然后这个构造函数把控制权传送给</span><span lang="EN-US">System.Object</span><span style="FONT-FAMILY: 宋体">默认构造函数。现在执行这些构造函数,首先执行</span><span lang="EN-US">System.Object</span><span style="FONT-FAMILY: 宋体">构造函数,接着执行</span><span lang="EN-US">Nevermore60 Customer</span><span style="FONT-FAMILY: 宋体">构造函数,初始化</span><span lang="EN-US">name</span><span style="FONT-FAMILY: 宋体">字段。然后带有两个参数的</span><span lang="EN-US">Nevermore60Customer</span><span style="FONT-FAMILY: 宋体">构造函数得到控制权,把联系人的姓名初始化为</span><span lang="EN-US"><None></span><span style="FONT-FAMILY: 宋体">。最后,执行</span><span lang="EN-US">Nevermore60 Customer</span><span style="FONT-FAMILY: 宋体">构造函数,该构造函数带有</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体">个参数<span style="LETTER-SPACING: -1pt">——</span></span><span style="LETTER-SPACING: -1pt"> </span><span style="FONT-FAMILY: 宋体">这个构造函数什么也不做。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">这个过
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?