100165824.htm

来自「C#高级编程(第三版),顶死你们。。 。up」· HTM 代码 · 共 251 行 · 第 1/5 页

HTM
251
字号
<p class="a6" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static explicit operator Currency (float value)</span></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; checked</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint dollars = (uint)value;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ushort cents = Convert.ToUInt16((value</span><span style="FONT-FAMILY: 宋体">&ndash;</span><span lang="EN-US">dollars)*100);</span></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new Currency(dollars, cents);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p class="a6" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">注意,使用</span><span lang="EN-US">Convert.ToUInt16()</span><span style="FONT-FAMILY: 宋体">计算小数,如上所示,但没有使用它计算数字的美元部分。在计算美元值时不需要使用</span><span lang="EN-US">System.Convert</span><span style="FONT-FAMILY: 宋体">,因为在此我们希望截去</span><span lang="EN-US">float</span><span style="FONT-FAMILY: 宋体">值。</span></p>
<p class="a3" style="MARGIN-TOP: 8.15pt; TEXT-INDENT: 21.45pt"><span style="FONT-FAMILY: 黑体">注意:</span></p>
<p class="a1" style="MARGIN-BOTTOM: 8.15pt; TEXT-INDENT: 21.45pt"><span lang="EN-US">System.Convert</span><span style="FONT-FAMILY: 楷体_GB2312">方法还执行它们自己的溢出检查。因此对于本例的情况,不需要把<span style="LETTER-SPACING: 0.2pt">对</span></span><span lang="EN-US" style="LETTER-SPACING: 0.2pt">Convert.ToUInt16()</span><span style="FONT-FAMILY: 楷体_GB2312; LETTER-SPACING: 0.2pt">的调用放在</span><span lang="EN-US">checked</span><span style="FONT-FAMILY: 楷体_GB2312; LETTER-SPACING: 0.2pt">环境下。但把</span><span lang="EN-US" style="LETTER-SPACING: 0.2pt">value</span><span style="FONT-FAMILY: 楷体_GB2312; LETTER-SPACING: 0.2pt">显式转换为美元值仍需要</span><span lang="EN-US" style="LETTER-SPACING: 0.2pt">checked</span><span style="FONT-FAMILY: 楷体_GB2312; LETTER-SPACING: 0.2pt">环境。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">这里没有给出这个新</span><span lang="EN-US">checked</span><span style="FONT-FAMILY: 宋体">转换的结果,因为在本节后面还要对</span><span lang="EN-US">SimpleCurrency</span><span style="FONT-FAMILY: 宋体">示例进行一些修改。</span></p>
<p class="a3" style="MARGIN-TOP: 8.15pt; TEXT-INDENT: 21.45pt"><span style="FONT-FAMILY: 黑体">注意:</span></p>
<p class="a1" style="MARGIN-BOTTOM: 8.15pt; TEXT-INDENT: 21.45pt"><span style="FONT-FAMILY: 楷体_GB2312">如果定义了一个使用非常频繁的数据类型转换,其性能也非常好,就可以不进行任何错误<span style="LETTER-SPACING: 0.1pt">检查,如果对用户定义的转换和没有检查的错误进行了清晰的说明,这也是一种合法的解决方</span>案。</span></p>
<h4 style="TEXT-INDENT: 21.45pt"><span lang="EN-US">1. </span><span style="FONT-FAMILY: 黑体">类之间的数据类型转换</span></h4>
<p class="MsoNormal"><span><span lang="EN-US">Currency</span></span><span style="FONT-FAMILY: 宋体">示例仅涉及到与</span><span lang="EN-US">float</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></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; TEXT-INDENT: -37.55pt"><span lang="EN-US"><span class="msoIns"><ins cite="mailto:Simon%20Robinson" datetime="2001-06-02T06:26"><strike><font color="#ff0000">q</font></strike>●<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></ins></span></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></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; TEXT-INDENT: -37.55pt"><span lang="EN-US"><span class="msoIns"><ins cite="mailto:Simon%20Robinson" datetime="2001-06-02T06:26"><strike><font color="#ff0000">q</font></strike>●<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></ins></span></span><span style="FONT-FAMILY: 宋体">数据类型转换必须在源或目标数据类型定义的内部定义。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">要说明这些要求,假定有如图</span><span lang="EN-US">5-1</span><span style="FONT-FAMILY: 宋体">所示的类层次结构。</span></p>
<p class="a0" align="center"><span lang="EN-US"><img height="143" alt="" width="97" src="05/image001.gif" /></span></p>
<p class="a" style="MARGIN-BOTTOM: 8.15pt" align="center"><span style="FONT-FAMILY: 宋体">图</span><span lang="EN-US">&nbsp; 5-1 </span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">换言之,类</span><span lang="EN-US">C</span><span style="FONT-FAMILY: 宋体">和</span><span lang="EN-US">D</span><span style="FONT-FAMILY: 宋体">间接派生于</span><span lang="EN-US">A</span><span style="FONT-FAMILY: 宋体">。在这种情况下,在</span><span lang="EN-US">A</span><span style="FONT-FAMILY: 宋体">、</span><span lang="EN-US">B</span><span style="FONT-FAMILY: 宋体">、</span><span lang="EN-US">C</span><span style="FONT-FAMILY: 宋体">或</span><span lang="EN-US">D</span><span style="FONT-FAMILY: 宋体">之间惟一合法的类型转换就是类</span><span lang="EN-US">C</span><span style="FONT-FAMILY: 宋体">和</span><span lang="EN-US">D</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></p>
<p class="2" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public static explicit operator D(C value)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // and so on</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public static explicit operator C(D value)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // and so on</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">对于这些数据类型转换,可以选择放置定义的地方<span style="LETTER-SPACING: -1pt">&mdash;&mdash;</span></span><span style="LETTER-SPACING: -1pt"> </span><span style="FONT-FAMILY: 宋体">在</span><span lang="EN-US">C</span><span style="FONT-FAMILY: 宋体">的类定义内部,或者在</span><span lang="EN-US">D</span><span style="FONT-FAMILY: 宋体">的类定义内部,但不能在其他地方定义。</span><span lang="EN-US">C#</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">(</span><span style="FONT-FAMILY: 宋体">或结构</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">的内部。它的边界效应是不能定义两个类之间的数据类型转换,除非可以编辑它们的源代码。这是因为,这样可以防止第三方把数据类型转换引入类中。</span></p>
<p class="MsoNormal"><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 style="FONT-FAMILY: 宋体">要了解这些数据类型转换是如何工作的,首先看看源和目标的数据类型都是引用类型,再考虑两个类</span><span lang="EN-US">MyBase </span><span style="FONT-FAMILY: 宋体">和</span><span lang="EN-US"> MyDerived</span><span style="FONT-FAMILY: 宋体">,其中</span><span lang="EN-US">MyDerived</span><span style="FONT-FAMILY: 宋体">直接或间接派生于</span><span lang="EN-US">MyBase</span><span style="FONT-FAMILY: 宋体">。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">首先是从</span><span lang="EN-US">MyDerived </span><span style="FONT-FAMILY: 宋体">到</span><span lang="EN-US"> MyBase</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></p>
<p class="2" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">MyDerived derivedObject = new MyDerived();</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">MyBase baseCopy = derivedObject;</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">在本例中,是从</span><span lang="EN-US">MyDerived </span><span style="FONT-FAMILY: 宋体">隐式地转换为</span><span lang="EN-US"> MyBase</span><span style="FONT-FAMILY: 宋体">。这是因为对类</span><span lang="EN-US">MyBase</span><span style="FONT-FAMILY: 宋体">的任何引用都可以引用类</span><span lang="EN-US">MyBase</span><span style="FONT-FAMILY: 宋体">的对象或派生于</span><span lang="EN-US">MyBase</span><span style="FONT-FAMILY: 宋体">的对象。在</span><span lang="EN-US">OO</span><span style="FONT-FAMILY: 宋体">编程中,派生类的实例实际上是<span style="LETTER-SPACING: 0.1pt">基类的实例,但加上了一些额外的信息。在基类上定义的所有函数和字段也都在派生类上定义了。</span></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">MyBase derivedObject = new MyDerived();</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">MyBase baseObject = new MyBase();</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">MyDerived derivedCopy1 = (MyDerived) derivedObject;&nbsp;&nbsp; // OK</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">MyDerived derivedCopy2 = (MyDerived) baseObject;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Throws exception</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">上面的代码都是合法的</span><span lang="EN-US">C#</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">(</span><span style="FONT-FAMILY: 宋体">或者派生于这个类的其他类</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">的一个实例,转换就会失败,抛出一个异常。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">注意,编译器已经提供了基类和派生类之间的转换,这种转换实际上并没有对对象进行任何数据转换。如果要进行的转换是合法的,它们也仅是把新引用设置为对对象的引用。这些转换在本质上与自己定义的转换不同。例如,在前面的</span><span lang="EN-US">SimpleCurrency</span><span style="FONT-FAMILY: 宋体">示例中,我们定义了</span><span lang="EN-US">Currency</span><span style="FONT-FAMILY: 宋体">结构和</span><span lang="EN-US">float</span><span style="FONT-FAMILY: 宋体">之间的转换,在</span><span lang="EN-US">float</span><span style="FONT-FAMILY: 宋体">到</span><span lang="EN-US">Currency</span><span style="FONT-FAMILY: 宋体">的转换中,则创建了一个新</span><span lang="EN-US">Currency</span><span style="FONT-FAMILY: 宋体">结构,并用要求的值进行初始化。在基类和派生类之间的预定义转换则不是这样。如果要把</span><span lang="EN-US">MyBase</span><span style="FONT-FAMILY: 宋体">实例转换为</span><span lang="EN-US">MyDerived</span><span style="FONT-FAMILY: 宋体">对象,其值根<span style="LETTER-SPACING: 0.2pt">据</span></span><span lang="EN-US" style="LETTER-SPACING: 0.2pt">MyBase</span><span style="FONT-FAMILY: 宋体; LETTER-SPACING: 0.2pt">实例的内容来确定,就不能使用数据类型转换语法,最合适的选项通常是定义一个派生类的构造函数,它的参数是一个基类实例,让这个构造函数执行相关的初始化:</span></p>
<p class="2" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">class DerivedClass : BaseClass</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">&nbsp;&nbsp; public DerivedClass(BaseClass rhs)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // initialize object from the Base instance</span></p>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?