100165824.htm
来自「C#高级编程(第三版),顶死你们。。 。up」· HTM 代码 · 共 251 行 · 第 1/5 页
HTM
251 行
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> uint dollars = (uint)value;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> ushort cents = (ushort)((value</span><span style="FONT-FAMILY: 宋体">–</span><span lang="EN-US">dollars)*100);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> return new Currency(dollars, cents);</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="2" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> float amount = 45.63f;</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> Currency amount2 = (Currency)amount;</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"> float amount = 45.63f;</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> Currency amount2 = amount; // wrong</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">把数据类型转换声明为显式,就是警告开发人员要小心,因为可能会丢失数据。但这不是我们希望的</span><span lang="EN-US">Currency</span><span style="FONT-FAMILY: 宋体">结构的执行方式。下面编写一个测试程序,运行示例。其中有一个</span><span lang="EN-US">Main()</span><span style="FONT-FAMILY: 宋体">方法,它实例化了一个</span><span lang="EN-US">Currency</span><span style="FONT-FAMILY: 宋体">结构,试图进行几个转换。在这段代码的开头,以两种不同的方式计算</span><span lang="EN-US">balance</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">static void Main()</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"> try</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"> Currency balance = new Currency(50,35);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt; LINE-HEIGHT: 15pt"><span lang="EN-US"> Console.WriteLine(balance);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt; LINE-HEIGHT: 15pt"><span lang="EN-US"> Console.WriteLine("balance is " + balance);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt; LINE-HEIGHT: 15pt"><span lang="EN-US"> Console.WriteLine("balance is (using ToString()) " +</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt; LINE-HEIGHT: 15pt"><span lang="EN-US"> balance.ToString());</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt; LINE-HEIGHT: 15pt"><span lang="EN-US"> float balance2= balance;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt; LINE-HEIGHT: 15pt"><span lang="EN-US"> Console.WriteLine("After converting to float, = " + balance2);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt; LINE-HEIGHT: 15pt"><span lang="EN-US"> balance = (Currency) balance2;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt; LINE-HEIGHT: 15pt"><span lang="EN-US"> Console.WriteLine("After converting back to Currency, = " + balance);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt; LINE-HEIGHT: 15pt"><span lang="EN-US"> </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> Console.WriteLine("Now attempt to convert out of range value of " +</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> "</span><span style="FONT-FAMILY: 宋体">–</span><span lang="EN-US">$100.00 to a Currency:");</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> checked</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"> balance = (Currency) (</span><span style="FONT-FAMILY: 宋体">–</span><span lang="EN-US">50.5);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US"> Console.WriteLine("Result is " + balance.ToString());</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"> catch(Exception e)</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"> Console.WriteLine("Exception occurred: " + e.Message);</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">try</span><span style="FONT-FAMILY: 宋体">块中,来捕获在数据类型转换过程中发生的任何异常。在</span><span lang="EN-US">checked</span><span style="FONT-FAMILY: 宋体">块中还添加了把超出范围的值转换为</span><span lang="EN-US">Currency</span><span style="FONT-FAMILY: 宋体">的测试代码,所以,负值是肯定会被捕获的。运行这段代码,得到如下所示的结果:</span></p>
<p class="a6" style="MARGIN: 8.15pt 0cm 6pt 9.95pt; TEXT-INDENT: 9.95pt"><strong><span lang="EN-US">SimpleCurrency</span></strong></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">50.35</span></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">Balance is $50.35</span></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">Balance is (using ToString()) $50.35</span></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">After converting to float, = 50.35</span></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">After converting back to Currency, = $50.34</span></p>
<p class="a6" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">Now attempt to convert out of range value of</span><span style="FONT-FAMILY: 宋体">–</span><span lang="EN-US">$100.00 to a Currency:</span></p>
<p class="a6" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">Result is $4294967246.60486</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><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">$50.34</span><span style="FONT-FAMILY: 宋体">,而不是</span><span lang="EN-US">$50.35</span><span style="FONT-FAMILY: 宋体">。其次,在试图转换明显超出范围的值时,没有生成异常。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">第一个问题是由圆整错误引起的。如果类型转换用于把</span><span lang="EN-US">float</span><span style="FONT-FAMILY: 宋体">转换为</span><span lang="EN-US">uint</span><span style="FONT-FAMILY: 宋体">,计算机就会截去多余的数字,而不是圆整它。计算机以二进制方式存储数字,而不是十进制,小数部分</span><span lang="EN-US">0.35</span><span style="FONT-FAMILY: 宋体">不能用二进制小数来表示</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">像</span><span lang="EN-US">1/3</span><span style="FONT-FAMILY: 宋体">这样的小数不能表示为小数部分,它应等于循环小数</span><span lang="EN-US">0.3333)</span><span style="FONT-FAMILY: 宋体">。所以,计算机最后存储了一个略小于</span><span lang="EN-US">0.35</span><span style="FONT-FAMILY: 宋体">的值,它可以用二进制格式表示。把该数字乘以</span><span lang="EN-US">100</span><span style="FONT-FAMILY: 宋体">,就会得到一个小于</span><span lang="EN-US">35</span><span style="FONT-FAMILY: 宋体">的数字,截去了美分</span><span lang="EN-US">34</span><span style="FONT-FAMILY: 宋体">,显然在本例中,这种由截去引起的错误是很严重的,避免该错误的方式是确保在数字转换过程中执行智能圆整操作。</span><span lang="EN-US">Microsoft</span><span style="FONT-FAMILY: 宋体">编写了一个类</span><span lang="EN-US">System.Convert</span><span style="FONT-FAMILY: 宋体">来完成该任务。</span><span lang="EN-US">System.Convert</span><span style="FONT-FAMILY: 宋体">包含大量的静态方法来执行各种数字转换,我们需要使用的是</span><span lang="EN-US">Convert.To UInt16()</span><span style="FONT-FAMILY: 宋体">。注意,在使用</span><span lang="EN-US">System.Convert</span><span style="FONT-FAMILY: 宋体">方法时会产生额外的性能损失,所以只应在需要时才使用它们。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span></span><span><span style="FONT-FAMILY: 宋体">下面看看为什么没有抛出期望的溢出异常。此处的问题是异常实际发生的位置根本不在</span><span lang="EN-US">Main()</span></span><span style="FONT-FAMILY: 宋体">例程中——这是在转换运算符的代码中发生的,该代码在</span><span lang="EN-US">Main()</span><span style="FONT-FAMILY: 宋体">方法中调用,而且没有标记为</span><span lang="EN-US">checked</span><span style="FONT-FAMILY: 宋体">。</span></p>
<p class="MsoNormal" style="LINE-HEIGHT: 17pt"><span style="FONT-FAMILY: 宋体">其解决方法是确保类型转换本身也在</span><span lang="EN-US">checked</span><span style="FONT-FAMILY: 宋体">环境下进行。进行了这两个修改后,修订后的转换代码如下所示。</span></p>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?