为什么Cast(CType/DirectCast)控件与隐式转换

Evi*_*lDr 3 vb.net asp.net asp.net-4.5

假设我在webforms GridViewRow中有一个控件...

<asp:Literal ID="ltl_abc" runat="server" />
Run Code Online (Sandbox Code Playgroud)

在RowDataBound事件中,我可以使用以下任何方法访问控件.我一直以来一直使用DirectCast:

Protected Sub gv_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles gv.RowDataBound
    Select Case e.Row.RowType
        Case DataControlRowType.DataRow
            ' 1) Dim ltl_abc As Literal = DirectCast(e.Row.FindControl("ltl_abc"), Literal)
            ' 2) Dim ltl_abc As Literal = CType(e.Row.FindControl("ltl_abc"), Literal)
            ' 3) Dim ltl_abc As Literal = e.Row.FindControl("ltl_abc")
Run Code Online (Sandbox Code Playgroud)

使用任何特定方法有什么好处吗?我猜DirectCast稍微有点效率,但可能容易出错,但隐式转换是否有任何危险(选项3)?

从历史上看,在我尝试为控件的属性实际赋值之前,我从未见过任何错误,这让我觉得这第一步不是那么重要吗?

请注意,这不是DirectCast与CType的讨论,更多的是关于在这里是否需要施法?

更新清晰

Protected Sub gv_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles gv.RowDataBound
    Select Case e.Row.RowType
        Case DataControlRowType.DataRow

            ' This works fine, but no explicit casting is done:
            Dim ltl_abc As Literal = e.Row.FindControl("ltl_abc") ' no (explicit) cast
            ltl_abc.Text = "Hello World"

            ' This also works until I try to access the object's properties
            Dim ltl_abc As Literal = DirectCast(e.Row.FindControl("NonExistentId"), Literal)
Run Code Online (Sandbox Code Playgroud)

那么为什么开发人员应该投射(在这个例子中),或者这个例子过于简单?

val*_*rij 8

对于您的情况,TryCast有一个IsNot Nothing检查可能会更加有利.

但是,要了解何时以及为何使用哪个,首先要看一下它们的MSDN定义.

DirectCast

介绍基于继承或实现的类型转换操作.... DirectCast 不使用Visual Basic运行时帮助程序进行转换 ...

CTYPE

返回将表达式显式转换为指定数据类型,对象,结构,类或接口的结果.

隐式转换

隐式转换不需要源代码中的任何特殊语法....显式转换使用类型转换关键字

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)
Run Code Online (Sandbox Code Playgroud)

第一个例子有效,因为obj已经是一个String刚被定义为Object.没有实际的转换.

现在让我们来看看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)
Run Code Online (Sandbox Code Playgroud)

最后,隐式转换:

' 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
Run Code Online (Sandbox Code Playgroud)

这两个都有用,但请记住,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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

所以,基本上,由于.NET需要调用外部方法来确定转换对象需要做什么,CType/ implicit将运行得稍慢(这里的示例基准和示例).注意,因为它们都在MSIL中编译相同,CType并且隐式转换应该执行相同的操作.

那么你什么时候使用它们?我通常遵循一些简单的规则

  1. 如果我知道(或期望)我的对象已经是我的目标类型,只是定义不同,我使用 DirectCast
  2. 如果我的对象类型不同于我的目标类型,我使用适当的Convert方法.示例:Dim myInt = CInt("42").注意,这CType与IL中的编译方式相同
  3. 如果我不确定传入类型,我会使用 TryCast
  4. 如果我使用泛型进行转换/转换,我将根据上下文使用DirectCast和/或Convert.ChangeType

你也可以CType在那里使用第二个,但在我看来,如果我知道我正在转换为a Integer,那么我会选择更明确的CInt.Option Strict但是,如果你有,那么如果你将错误的东西传递给任何一个,你应该得到一个构建错误.

此外,虽然你可能会想一些替代TryCastDirectCast有关重大分歧和使用的答案检查这太问题:为什么使用TryCast代替Directcast?

如果你注意到,那里我没有包含隐式输入.为什么?好吧,主要是因为我使用代码Option Strict On,并且在缩小类型时它并不真正允许隐式转换(请参阅"扩展和缩小转换").否则,就.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)
Run Code Online (Sandbox Code Playgroud)

还有一个:

' 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)
Run Code Online (Sandbox Code Playgroud)

因此,对于您的情况,它看起来像TryCast一个IsNot Nothing检查是要走的路.