经常地,你需要在不同的两个类型之间进行转换. For example, you might need to determine whether an Integer is greater or less than a Double. You might need to pass a Double to a method that requires an Integer as a parameter. Or you might need to display a number as text.
This lesson describes how to convert between types in both Visual Basic and C#. Type conversion is one of the few areas where Visual Basic and C# differ considerably.
Visual Basic 和 C# 的转换
默认情况下, Visual Basic 允许类型之间隐式转换, 但C# 禁止隐私转换,因为那样会导致丢失精度. To turn off implicit conversions in Visual Basic, add Option Strict On to the top of each code file, or (in Visual Studio) select Project, choose Properties, select Compile, and select Option Strict On for the entire project.
如果目标类型能够适应原类型的所有值,那么Visual Basic 和 C#都允许他们隐式转换. 这个被叫做 widening conversion,如下所示:
' VB
Dim i As Integer = 1
Dim d As Double = 1.0001
d = i ' Conversion allowed
// C#
int i = 1;
double d = 1.0001;
d = i; // Conversion allowed.
如果原类型的范围或者精度超过了目标类型, 这个操作叫做 narrowing conversion, 通常需要显示转换. Table 1-7 列出了显示转换的方法:
System Type | Visual Basic | C# | Converts |
---|---|---|---|
System.Convert | Between types that implement the System.IConvertible interface. | ||
CType | (type) cast operator | Between types that define conversion operators. | |
type.ToString, type.Parse | Between string and base types; throws exception if the conversion is not possible. | ||
type.TryParse, type.TryParseExact | From string to a base type; returns false if the conversion is not possible. | ||
CBool, CInt, CStr, etc. | Between base Visual Basic types; compiled inline for better performance. (Visual Basic only.) | ||
DirectCast, TryCast | Between types. DirectCast throws an exception if the types are not related through inheritance or if they do not share a common interface; TryCast returns Nothing in those situations. (Visual Basic only.) |
.NET 2.0 | TryParse, TryParseExact, and TryCast are new in .NET 2.0. Previously, you had to attempt a parsing or conversion and then catch the exception if it failed. |
显示转换有可能会失败,所以你需要使用 Try blocks 或 TryCast 或 TryParse,并且检查返回值.
什么是装箱和拆箱?
装箱把一个值类型转换成引用类型,拆箱正好相反. 下面的例子说明装箱操作把 Integer (一个值类型) 转换成 Object (一个引用类型):
'VB
Dim i As Integer = 123
Dim o As Object = CType(i, Object)
// C#
int i = 123;
object o = (object) i;
Unboxing occurs if you assign a reference object to a value type. The following example demonstrates unboxing:
'VB
Dim o As Object = 123
Dim i As Integer = CType(o, Integer)
// C#
object o = 123;
int i = (int) o;
Best Practices—Boxing and unboxing | Boxing and unboxing incur overhead, so you should avoid them when programming intensely repetitive tasks. Boxing also occurs when you call virtual methods that a structure inherits from System.Object, such as ToString. Follow these tips to avoid unnecessary boxing:
|
如何实现自定义类型转换?
You can define conversions for your own types in several ways. Which technique you choose depends on the type of conversion you want to perform:
-
Define conversion operators to simplify narrowing and widening conversions between numeric types.
-
Override ToString to provide conversion to strings, and override Parse to provide conversion from strings.
-
Implement System.IConvertible to enable conversion through System.Convert. Use this technique to enable culture-specific conversions.
-
Implement a TypeConverter class to enable design-time conversion for use in the Visual Studio Properties window. Design-time conversion is outside the scope of the exam and the TypeConverter class is not covered in this book.
More Info—Design-time conversion | For more information about design-time conversion, read "Extending Design-Time Support" at http://msdn2.microsoft.com/en-us/library/37899azc(en-US,VS.80).aspx. |
.NET 2.0 | Conversion operators are new in .NET 2.0. |
通过定义operators操作,允许你直接把一个值类型转换成自定义类型. Use the Widening/implicit keyword for conversions that don't lose precision; use the Narrowing/explicit keyword for conversions that could lose precision. For example, the following structure defines operators that allow assignment to and from integer values:
' VB
Structure TypeA
Public Value As Integer
' Allows implicit conversion from an integer.
Public Shared Widening Operator CType(ByVal arg As Integer) As TypeA
Dim res As New TypeA
res.Value = arg
Return res
End Operator
' Allows explicit conversion to an integer
Public Shared Narrowing Operator CType(ByVal arg As TypeA) As Integer
Return arg.Value
End Operator
' Provides string conversion (avoids boxing).
Public Overrides Function ToString() As String
Return Me.Value.ToString
End Function
End Structure
// C#
struct TypeA
{
public int Value;
// Allows implicit conversion from an integer.
public static implicit operator TypeA(int arg)
{
TypeA res = new TypeA();
res.Value = arg;
return res;
}
// Allows explicit conversion to an integer
public static explicit operator int(TypeA arg)
{
return arg.Value;
}
// Provides string conversion (avoids boxing).
public override string ToString()
{
return this.Value.ToString();
}
}
The preceding type also overrides ToString to perform the string conversion without boxing. Now you can assign integers to the type directly, as shown here:
' VB
Dim a As TypeA, i As Integer
' Widening conversion is OK implicit.
a = 42 ' Rather than a.Value = 42
' Narrowing conversion must be explicit.
i = CInt(a) ' Rather than i = a.Value
' This syntax is OK, too.
i = CType(a, Integer)
Console.WriteLine("a = {0}, i = {0}", a.ToString, i.ToString)
// C#
TypeA a; int i;
// Widening conversion is OK implicit.
a = 42; // Rather than a.Value = 42
// Narrowing conversion must be explicit.
i = (int)a; // Rather than i = a.Value
Console.WriteLine("a = {0}, i = {0}", a.ToString(), i.ToString());
To implement the System.IConvertible interface, add the IConvertible interface to the type definition. Then use Visual Studio to automatically implement the interface. Visual Studio inserts member declarations for 17 methods, including GetTypeCode, ChangeType, and ToType methods for each base type. You don't have to implement every method, and some-such as ToDateTime-will probably be invalid. For invalid methods, simply throw an exception-Visual Studio automatically adds code to throw an exception for any conversion methods you don't implement.
After you implement IConvertible, the custom type can be converted using the standard System.Convert class as shown here:
' VB
Dim a As TypeA, b As Boolean
a = 42
' Convert using ToBoolean.
b = Convert.ToBoolean(a)
Console.WriteLine("a = {0}, b = {1}", a.ToString, b.ToString)
// C#
TypeA a; bool b;
a = 42;
// Convert using ToBoolean.
b = Convert.ToBoolean(a);
Console.WriteLine("a = {0}, b = {1}", a.ToString(), b.ToString());
Lab: Safely Performing Conversions 安全执行转换
The following exercises show how to avoid problems with implicit conversions so that your programs function predictably. If you encounter a problem completing an exercise, the completed projects are available on the companion CD in the Code folder.
![]() |
In this exercise, you will examine conversion to determine which number types allow implicit conversion.
-
Create a new console application in Visual Studio.
-
Declare instances of three value types: Int16, Int32, and double. The following code sample demonstrates this:
' VB
Dim i16 As Int16 = 1
Dim i32 As Int32 = 1
Dim db As Decimal = 1
// C#
Int16 i16 = 1;
Int32 i32 = 1;
double db = 1; -
Attempt to assign each variable to all the others, as the following code sample demonstrates.
' VB
i16 = i32
i16 = db
i32 = i16
i32 = db
db = i16
db = i32
// C#
i16 = i32;
i16 = db;
i32 = i16;
i32 = db;
db = i16;
db = i32; -
Attempt to build your project. Which implicit conversions did the compiler allow, and why?
![]() |
![]() |
In this exercise, which is only for developers using Visual Basic, you will modify the compiler's options and then rebuild the project you created in Exercise 1.
-
In Visual Studio, open the project you created in Exercise 1.
-
Click the Project menu, and then click ProjectName Properties.
-
Click the Compile tab. For Implicit Conversion, change the Notification type to Error.
-
Attempt to build your project. Which implicit conversions did the compiler allow, and why?
![]() |
Lesson Summary
-
The .NET Framework can automatically convert between built-in types. Widening conversions occur implicitly in both Visual Basic and C#. Narrowing conversions require explicit conversion in C#, while Visual Basic allows narrowing conversions by default.
-
Boxing allows any type to be treated as a reference type.
-
You must specifically implement conversion operators to enable conversion in custom types.
Lesson Review
You can use the following questions to test your knowledge of the information in Lesson 4, "Converting Between Types." The questions are also available on the companion CD if you prefer to review them in electronic form.
Answers | Answers to these questions and explanations of why each answer choice is right or wrong are located in the "Answers" section at the end of the book. |
Why should boxing be avoided? (Choose one.)
| ||
Structures inherit ToString from System.Object. Why would someone override that method within a structure? (Choose as many correct answers as apply.)
| ||
If there is no valid conversion between two types, what should you do when implementing the IConvertible interface?
| ||
With strict conversions enabled, which of the following would allow an implicit conversion? (Choose all that apply.)
|
Answers
Correct Answer: A
| |
Correct Answers: A and B
| |
Correct Answer: B
| |
Correct Answers: A and C
|