对于您的情况,TryCast 带有IsNot Nothing 的检查可能更有益。
不过,要了解何时以及为何使用哪个,请先查看 MSDN 对它们的定义。
DirectCast
引入基于继承或实现的类型转换操作。 ... DirectCast 不使用 Visual Basic 运行时帮助程序进行转换...
CType
返回将表达式显式转换为指定数据类型、对象、结构、类或接口的结果。
Implicit Conversion
隐式转换不需要源代码中的任何特殊语法。 ...显式转换使用类型转换关键字
TryCast
引入了不抛出异常的类型转换操作。 ... TryCast 返回 Nothing (Visual Basic),因此您不必处理可能的异常,只需针对 Nothing 测试返回的结果。
脱离这些定义,我们可以假设CType 将根据给定的System.Type 进行外部调用,而DirectCast 将仅使用不同名字下的现有对象。同时,通过隐式转换,VB 只会尝试执行代码。然而,TryCast 将尝试强制转换对象或仅返回 Nothing(想想 C# 中的 as 运算符)
例如:
' works
Dim obj As Object = "I'm a string!" 'obj.GetType() -> System.String
Dim s = DirectCast(obj, String)
' throws error: Unable to cast object of type 'System.Int32' to type 'System.String'.
Dim obj As Object = 42 'obj.GetType() -> System.Int32
Dim s = DirectCast(obj, String)
第一个示例有效,因为obj 已经是刚刚定义为Object 的String。没有发生实际的转换。
现在让我们看看CType:
' works
Dim obj As Object = "I'm a string!" 'obj.GetType() -> System.String
Dim s = CType(obj, String)
' works - would prefer to use CStr() here instead, since it's more explicit (see below)
Dim obj As Object = 42 'obj.GetType() -> System.Int32
Dim s = CType(obj, String)
最后,隐式转换:
' works with Option Explicit. Throws build error with Option Strict: Option Strict On disallows implicit conversions from 'Object' to 'String'.
Dim obj As Object = "I'm a string!" 'obj.GetType() -> System.String
Dim s As String = obj
' same as above
Dim obj As Object = 42 'obj.GetType() -> System.Int32
Dim s As String = obj
这两种方法都有效,但请记住,VB.NET 在这里调用了一个单独的库来完成这项繁琐的工作:
DirectCast:
IL_0000: nop
IL_0001: ldstr "I'm a string!"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: castclass [mscorlib]System.String
IL_000d: stloc.1
IL_000e: nop
IL_000f: ret
CType/隐式转换(编译相同):
IL_0000: nop
IL_0001: ldstr "I'm a string!"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: call string [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToString(object)
IL_000d: stloc.1
IL_000e: nop
IL_000f: ret
因此,基本上,由于 .NET 需要调用外部方法来确定它需要做什么来转换对象,CType/implicit 的运行速度会稍慢(example benchmarks and examples here)。请注意,由于它们在 MSIL 中编译相同,CType 和隐式转换应该执行相同。
那么你什么时候使用它们呢?我通常遵循几个简单的规则
- 如果我知道(或期望)我的对象已经是我的目标类型,只是定义不同,我使用
DirectCast
- 如果我的对象与我的目标类型不同,我使用适当的转换方法。示例:
Dim myInt = CInt("42")。注意,它的编译方式与 IL 中的CType 相同
- 如果我不确定传入的类型,我使用
TryCast
- 如果我使用泛型进行强制转换/转换,我将使用
DirectCast 和/或 Convert.ChangeType,具体取决于上下文
您也可以使用CType 作为第二个,但在我看来,如果我知道我正在转换为Integer,那么我会选择更明确的CInt。但是,如果您启用了Option Strict,那么如果您将错误的内容传递给任一方式,您都应该会收到构建错误。
此外,虽然您可能想尝试用 TryCast 代替 DirectCast,但请查看有关主要差异和用途的 SO 问题的答案:Why use TryCast instead of Directcast?
如果您注意到,我没有在其中包含隐式输入。为什么?好吧,主要是因为我使用Option Strict On 进行编码,并且在缩小类型时它实际上不允许隐式转换(请参阅"Widening and Narrowing Conversions")。否则,就 .NET 而言,它与 CType 几乎相同
好的,现在所有这些都完成了,让我们看看所有三个(我猜是四个)Control 对象:
' control is just defined as a regular control
Dim control As New Control
' Runtime Error: Unable to cast object of type 'System.Web.UI.Control' to type 'System.Web.UI.LiteralControl'
Dim literal_1 As LiteralControl = DirectCast(control, LiteralControl)
' Runtime Error: Unable to cast object of type 'System.Web.UI.Control' to type 'System.Web.UI.LiteralControl'
Dim literal_2 As LiteralControl = CType(control, LiteralControl)
' returns literal_3 -> Nothing
Dim literal_3 As LiteralControl = TryCast(control, LiteralControl)
还有一个:
' control as a LiteralControl stored as a Control
Dim control As Control = New LiteralControl
' works
Dim literal_1 As LiteralControl = DirectCast(control, LiteralControl)
' works
Dim literal_2 As LiteralControl = CType(control, LiteralControl)
' works
Dim literal_3 As LiteralControl = TryCast(control, LiteralControl)
因此,对于您的情况,看起来TryCast 带有IsNot Nothing 检查是要走的路。