100165821.htm
来自「C#高级编程(第三版),顶死你们。。 。up」· HTM 代码 · 共 248 行 · 第 1/3 页
HTM
248 行
<p class="2" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span><span lang="EN-GB">long val = 30000;</span></span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">int i = (int)val; // A valid cast. The maximum int is 2147483647</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">C++</span><span style="FONT-FAMILY: 宋体">特殊数据类型转换关键字</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">如</span><span lang="EN-US">static_cast)</span><span style="FONT-FAMILY: 宋体">的程序员来说,这些关键字是</span><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">中不存在,必须使用旧的</span><span lang="EN-US">C</span><span style="FONT-FAMILY: 宋体">风格的语法。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">这种类型转换是一种比较危险的操作,即使在从</span><span lang="EN-US">long</span><span style="FONT-FAMILY: 宋体">转换为</span><span lang="EN-US">int</span><span style="FONT-FAMILY: 宋体">这样简单的转换过程中,如果原来</span><span lang="EN-US">long</span><span style="FONT-FAMILY: 宋体">的值比</span><span lang="EN-US">int</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-GB">long val = 3000000000;</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">int i = (int)val; // An invalid cast. The maximum int is 2147483647</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">在本例中,不会报告错误,也得不到期望的结果。如果运行上面的代码,结果存储在</span><span lang="EN-US">i</span><span style="FONT-FAMILY: 宋体">中,则其值为:</span></p>
<p class="a6" style="MARGIN: 8.15pt 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span style="FONT-FAMILY: 宋体">–</span><span lang="EN-US">1294967296</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">checked</span><span style="FONT-FAMILY: 宋体">运算符,使用它可以测试操作是否会产生算术溢出。使用这个运算符可以检查数据类型转换是否安全,如果不安全,就会让运行时抛出一个溢出异常:</span></p>
<p class="a6" style="MARGIN: 8.15pt 0cm 0pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">long val = 3000000000;</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">int i = checked ((int)val);</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">记住,所有的显式数据类型转换都可能不安全,在应用程序中应包含这样的代码,处理可能失败的数据类型转换。第</span><span lang="EN-US">11</span><span style="FONT-FAMILY: 宋体">章将使用</span><span lang="EN-US">try</span><span style="FONT-FAMILY: 宋体">和</span><span lang="EN-US"> catch</span><span style="FONT-FAMILY: 宋体">语句引入结构化异常处理。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">使用数据类型转换可以把大多数数据从一种基本类型转换为另一种基本类型。例如</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-GB">double price = 25.30;</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">int approximatePrice = (int)(price + 0.5);</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">这么做的代价是把价格四舍五入为最接近的美元数。但在这个转换过程中,小数点后面的所有数据都会丢失。因此,如果要使用这个修改过的价格进行更多的计算,最好不要使用这种转换;如果要输出全部计算完或部分计算完的近似值,<span style="LETTER-SPACING: -0.5pt">且如果</span>不希望用小数点后面的数据去麻烦用户,这种转换是很好的。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">这个例子说明了把一个无符号的整数转换为</span><span lang="EN-US">char</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-GB">ushort c = 43;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">char symbol = (char)c;</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">Console.WriteLine(symbol);</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">结果是</span><span lang="EN-US">ASCII</span><span style="FONT-FAMILY: 宋体">数为</span><span lang="EN-US">43</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">char)</span><span style="FONT-FAMILY: 宋体">,这种转换是成功的,例如把</span><span lang="EN-US">decimal</span><span style="FONT-FAMILY: 宋体">转换为</span><span lang="EN-US">char</span><span style="FONT-FAMILY: 宋体">,或把</span><span lang="EN-US">char</span><span style="FONT-FAMILY: 宋体">转换为</span><span lang="EN-US">decimal</span><span style="FONT-FAMILY: 宋体">。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">值类型之间的转换并不仅限于孤立的变量。还可以把类型为</span><span lang="EN-US">double</span><span style="FONT-FAMILY: 宋体">的数组元素转换为类型为</span><span lang="EN-US">int</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-GB">struct ItemDetails </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB"> public string Description;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB"> public int ApproxPrice;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">}</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB"> </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">//...</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB"> </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">double[] Prices = { 25.30, 26.20, 27.40, 30.00 };</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB"> </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">ItemDetails id;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">id.Description = "Whatever";</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-GB">id.ApproxPrice = (int)(Prices[0] + 0.5);</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">使用显式的数据类型转换方式,并小心使用这种技术,就可以把简单的值类型的任何实例转换为另一种类型。但在进行显式的类型转换时有一些限制,例如值类型,只能在数字、</span><span lang="EN-US">char</span><span style="FONT-FAMILY: 宋体">类型和</span><span lang="EN-US">enum</span><span style="FONT-FAMILY: 宋体">类型之间转换。不能直接把</span><span lang="EN-US">Boolean</span><span style="FONT-FAMILY: 宋体">数据类型转换为其他类型,也不能把其他类型转换为</span><span lang="EN-US">Boolean</span><span style="FONT-FAMILY: 宋体">数据类型。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">如果需要在数字和字符串之间转换,</span><span lang="EN-US">.NET</span><span style="FONT-FAMILY: 宋体">类库提供了一些方法。</span><span lang="EN-US">Object</span><span style="FONT-FAMILY: 宋体">类有一个</span><span lang="EN-US">ToString()</span><span style="FONT-FAMILY: 宋体">方法,该方法在所有的</span><span lang="EN-US">.NET</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">int i = 10;</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">string s = i.ToString();</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">同样,如果需要分析一个字符串,获得一个数字或</span><span lang="EN-US">Boolean</span><span style="FONT-FAMILY: 宋体">值,就可以使用所有预定义值类型都支持的</span><span lang="EN-US">Parse</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">string s = "100";</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">int i = int.Parse(s);</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">Console.WriteLine(i + 50); // Add 50 to prove it is really an int</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">注意,如果不能转换字符串</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">例如要把字符串</span><span lang="EN-US">Hello</span><span style="FONT-FAMILY: 宋体">转换为一个整数</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">,</span><span lang="EN-US">Parse</span><span style="FONT-FAMILY: 宋体">方法就会注册一个错误,抛出一个异常。第</span><span lang="EN-US">11</span><span style="FONT-FAMILY: 宋体">章将介绍异常。</span></p>
<h3 style="MARGIN: 8.15pt 0cm"><span><span lang="EN-GB">5.2.2 </span></span><span style="FONT-FAMILY: 黑体">装箱和</span><span style="FONT-FAMILY: 黑体">取消装箱</span></h3>
<p class="MsoNormal"><span><span style="FONT-FAMILY: 宋体">第</span><span lang="EN-US">2</span></span><span style="FONT-FAMILY: 宋体">章介绍了所有类型,包括简单的预定义类型,例如</span><span lang="EN-US">int</span><span style="FONT-FAMILY: 宋体">和</span><span lang="EN-US">char</span><span style="FONT-FAMILY: 宋体">,以及复合类型,例如从</span><span lang="EN-US">Object</span><span style="FONT-FAMILY: 宋体">类型中派生的类和结构。下面可以像处理对象那样处理字面值:</span></p>
<p class="2" style="MARGIN: 8.15pt 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">string s = 10.ToString();</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">int</span><span style="FONT-FAMILY: 宋体">不过是堆栈上一个</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体">字节的值,该如何在它上面调用方法?</span></p>
<p class="MsoNormal"><span lang="EN-US">C#</span><span style="FONT-FAMILY: 宋体">的实现方式是通过一个有点魔术性的方式,即装箱</span><span lang="EN-US">(boxing)</span><span style="FONT-FAMILY: 宋体">。装箱和取消装箱</span><span lang="EN-US">(unboxing)</span><span style="FONT-FAMILY: 宋体">可以把值类型转换为引用类型,或把引用类型转换为值类型。这已经在数据类型转换一节中介绍过了,即把值转换为</span><span lang="EN-US">object</span><span style="FONT-FAMILY: 宋体">类型。装箱用于描述把一个值类型转换为引用类型。运行库会为堆上的对象创建一个临时的引用类型“</span><span lang="EN-US">box</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><span lang="EN-US">int i = 20;</span></span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">object o = i;</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">取消装箱用于把引用类型转换为值类型,其中引用类型的值转换为值类型。这里使用术语</span><span lang="EN-US">"</span><span style="FONT-FAMILY: 宋体">“</span><span lang="EN-US">cast</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">int i = 20;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">object o = i; // Box the int</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">int j = (int)o; // Unbox it back into an int</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">只能把以前装箱的变量再转换为值类型。当</span><span lang="EN-US">o</span><span style="FONT-FAMILY: 宋体">不是装箱后的</span><span lang="EN-US">int</span><span style="FONT-FAMILY: 宋体">型时,如果执行最后一行,就会抛出一个异常。</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">int</span><span style="FONT-FAMILY: 宋体">只有</span><span lang="EN-US">32</span><span style="FONT-FAMILY: 宋体">位,所以把</span><span lang="EN-US">long</span><span style="FONT-FAMILY: 宋体">值类型</span><span lang="EN-US">(64</span><span style="FONT-FAMILY: 宋体">位</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">转换为</span><span lang="EN-US">int</span><span style="FONT-FAMILY: 宋体">时,会产生一个</span><span lang="EN-US">InvalidCastException</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">long a = 333333423;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">object b = (object)a;</span></p>
<p class="2" style="MARGIN: 0cm 0cm 8.15pt 21.45pt; TEXT-INDENT: 18.45pt"><span lang="EN-US">int c = (int)b;</span></p></div>
<!-- page -->
<div class="page" style="text-align: center">
<a href="100165820.htm">上一页</a> <a href="index.html">首页</a> <a href="100165822.htm">下一页</a>
</div>
<div style="margin: 0px auto; width: 700px; border: solid 1px #0b5f98;">
<div style="float: left; width: 16px; background-color: #0b5f98; color: White; padding: 1px;">
图书导读
</div>
<div style="float: right; width: 670px; text-align: left; line-height: 16pt; padding-left: 2px">
<!--导读-->
<h1 id="divCurrentNode2" style="color: #b83507; width: 100%; text-align: left; font-size: 12px; padding-left: 2px">当前章节:<a href='100165821.htm'><font color='red'>5.2 类型的安全性</font></a></h1>
<div id="divRealteNod2" style="padding-left: 2px">
<div style='float:left;width:49%'>·<a href='100165818.htm'>4.3 修饰符</a></div><div style='float:right;width:49%'>·<a href='100165819.htm'>4.4 接口</a></div><div style='float:left;width:49%'>·<a href='100165820.htm'>5.1 运算符</a></div><div style='float:right;width:49%'>·<a href='100165822.htm'>5.3 对象的相等比较</a></div><div style='float:left;width:49%'>·<a href='100165823.htm'>5.4 运算符重载</a></div><div style='float:right;width:49%'>·<a href='100165824.htm'>5.5 用户定义的数据类型转换</a></div></div>
</div>
</div>
</div></div>
</body>
</html>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?