2013-12-12 47 views
3

假设我有一个web表单内的控制GridViewRow ...为什么演员(类型/ DirectCast)对照组与隐式转换

<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 VS 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

** 3)**是否使用Option Strict? (这里不是一个VB.NET的人,但我认为这是一个推荐使用的东西。)因为如果不是这样,那么这个问题应该减少到“我应该使用Option Strict吗?”,这对于我来说是有问题的。 – millimoose

+0

我用显式,根据MSDN暗示严格,是的,它的工作原理。但我认为这是因为该变量被宣布为** Literal ** – EvilDr

+0

它甚至可以在控件不存在的情况下工作(直到您尝试为属性赋值时才抛出Null引用),'Dim fakeCtrl as Literal = e.Row.FindControl(“NotThere”)' – EvilDr

回答

8

对于您的情况,TryCastIsNot 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 

类型/隐式转换(编译相同):

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 /隐式会运行得稍慢(example benchmarks and examples here)。请注意,由于它们都在MSIL中编译相同,所以CType和隐式转换应该执行相同。

那么你什么时候使用它们?我一般遵循几个简单的规则

  1. 如果我知道(或希望)我的对象已经是我的目标类型,只是有不同的定义,我用DirectCast
  2. 如果我的对象是不同类型的比我的目标类型,我使用适当的Convert方法。例如:Dim myInt = CInt("42")。请注意,这个编译一样CType在IL
  3. 如果我不确定输入型的,我用TryCast
  4. 如果我铸件/泛型转换,我将使用DirectCast和/或Convert.ChangeType,根据上下文

您也可以使用CType对于第二个那里,但在我看来,如果我知道我转换为Integer,那么我会选择更明确CInt。但是,如果你有Option Strict,那么如果你把错误的东西传入任何一个,你都会得到一个构建错误。

此外,虽然你可能会想一些关于重大分歧的DirectCast检查答案代TryCast到这太问题及用途: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) 

因此,对于您的情况,它看起来像TryCastIsNot Nothing检查是要走的路。

+1

这是一个关于CType,TryCast和DirectCast的非常好的讨论;然而,OP特别表示他们也想覆盖隐式投射。您可能想要添加一些关于隐式投射行为的内容,以及何时以及为什么要优先考虑您已经覆盖的任何内容。 – JamieSee

+1

@JamieSee,很好,我已经更新了我的例子。 – valverij

+1

@EvilDr,我已经更新了答案,以包含隐式转换的信息和一个使用web控件的例子。 – valverij

1

你可能想看看这里的答案:

https://stackoverflow.com/a/3056582/117215

至于你的问题的一部分归结为DirectCast与CTYPE。

,为什么你不应该使用隐式转换,你已经叫了一些缺点,在你的问题(即,如果没有找到工作等)。

+1

这是一个有用的链接,但与他的问题无关。他说:“请注意,这不是一个DirectCast vs CType的讨论,更关于在这里是否需要投射? –

0

DirectCast()是最有效,最快捷的,但是当目标不是正是你所寻找的,或空的类型会抛出异常。

TryCast()(你没有列出)几乎与DirectCast()一样,但从不抛出异常,而是返回null。

CType()效率不高,并且如果没有转换为所述目标对象和所述目标对象之间的类型可用只会抛出异常。如果存在转换,那么它将运行该转换,并且如果目标为空,该转换可能会失败。

显式不会为您自动执行转换,并且如果类型不是完全匹配(IE,将数组分配给IEnumerable变量),并且不会抛出异常,并且如果目标是空值。因此,稍后尝试访问该对象时可能会出现异常。所以它非常接近TryCast(),而没有将对象分配给兼容对象的问题。

对于你的例子,我建议DirectCast()与一些异常处理。

+0

'DirectCast()...将在目标为... null.'时抛出异常。它似乎没有,如果我做'Dim lbl As Label = DirectCast(e.Row.FindControl(“NonExistentControlId”),Label)',那工作正常,直到我试图实际访问对象的属性。 – EvilDr

1

要回答你是否需要铸造的问题,“它取决于”。

在您给出的例子中,这是必要的,因为您声明的变量类型为Literal

FindControl方法返回Control,其中Literal继承自。因此,假设您不需要访问任何特定于Literal的属性或方法,则可以设想将ltl_abc声明为Control(并因此避免将其转换为Literal)。

+0

谢谢道格拉斯。你说'[转换]是必要的,因为你将变量声明为类型为Literal'但是例如'3)',它在没有执行转换时有效'Dim ltl_abc As Literal = e.Row.FindControl(“ltl_abc”)' (我认为这是在后台隐式完成的)。我知道如果声明为'Control',但是必须使用'Literal'控件的属性/方法,但是在'3'中实际发生的事情,我必须投入'Literal'。 – EvilDr

+0

在示例#3中,VB正在执行从“Control”到“Literal”的隐式转换。另外,如果演员阵容失败(例如,如果你在'TextBox'而不是'Literal'上执行它),那么它会抛出一个'InvalidCastException'。 –

相关问题