假设我在webforms GridViewRow中有一个控件...
<asp:Literal ID="ltl_abc" runat="server" />
在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")
使用任何特定方法有什么好处吗?我猜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)
为什么开发人员应该投射(在这个例子中),或者这个例子过于简单?
答案 0 :(得分:8)
对于您的情况,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
已经是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)
最后,隐式转换:
' 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
的{{1}}检查是可行的。
答案 1 :(得分:1)
您可能希望在此处查看答案:
https://stackoverflow.com/a/3056582/117215
作为问题的一部分归结为DirectCast与CType。
至于为什么你不应该使用隐式强制转换,你已经在你的问题中找到了一些缺点(即如果找不到则可以工作等)。
答案 2 :(得分:1)
要回答关于是否需要施法的问题,“它取决于”。
在您给出的示例中,有必要因为您将变量声明为Literal
类型。
FindControl
方法返回Control
,Literal
继承自ltl_abc
。因此,假设您不需要访问任何属性或方法,您可以将Control
声明为Literal
(从而避免将其强制转换为Literal
)特定于{{1}}。
答案 3 :(得分:0)
DirectCast()
是最有效和最快速的,但是当目标不是您正在寻找的类型时会抛出异常,或者为null。
TryCast()
(你没有列出)与DirectCast()
几乎相同,但从不抛出异常,而是返回null。
CType()
效率较低,如果目标对象和目标对象类型之间没有可用的转换,则只会抛出异常。如果存在转换,那么它将运行该转换,如果目标为空,则转换可能会失败。
Explicit不会自动执行转换,如果类型不是完全匹配(IE,将数组分配给IEnumerable变量),则不会抛出异常,如果目标为null,则不会抛出异常。因此,稍后尝试访问该对象时可能会出现异常。所以它非常接近TryCast()
而没有将对象分配给兼容对象的问题。
对于那里的例子,我建议DirectCast()
进行一些异常处理。