如何在VB.NET中将Object转换为Integer?

18

我应该如何在VB.NET中将一个Object转换为Integer

当我执行以下代码时:

Dim intMyInteger as Integer = TryCast(MyObject, Integer)

它说:

TryCast操作数必须是引用类型,但整数是值类型。


为什么不用这个:CInt(MyObject)? - Dave
@Dave - 请阅读我对Abacus答案的评论。CInt(或任何其他转换调用)与TryCast / DirectCast的目的不同。如果您有一个传入的数字值类型,例如Single或Double,并希望将其截断为整数,则可以使用它。将其应用于传入的“Object”意味着您不知道正在发生什么以及将尝试进行哪些转换工作。在我看来,这是一种冒险的编程风格。按照Jonathan所示的方法进行,必要时进行扩展。例如,如果您想要解析字符串,请检查其类型是否为字符串,然后调用TryParse。要明确。 - ToolmakerSteve
@Dave...希望最终在.Net中会有数字支持。例如,让所有数值类型支持一个INumeric(或其他)接口。鉴于此,我们可以拥有一个传入的MyNumber As INumeric而不是传入的MyObject As Object。好的,现在我们知道了关于传入内容的"足够"信息,可以执行CInt(MyNumber),并且有信心知道将要完成的工作。 - ToolmakerSteve
不要误解我的意思,我并不是建议避免使用转换运算符,我特别是在谈论将它们应用于“Object”时。我认为这是一种“代码异味”。我建议在确定了某个接口或基类之前不要使用转换运算符,这样你就知道自己要求做什么,以及可能出现的问题。了解你是否正在请求字符串解析、数字截断或仅仅是“拆箱”。 - ToolmakerSteve
4个回答

34

TryCast等同于C#中的as运算符。它是一种“安全转换”操作符,如果转换失败,不会抛出异常。相反,它返回Nothing(在C#中为null)。问题是,您不能将Nothingnull)(引用类型)赋值给Integer(值类型)。没有Integer null/Nothing这样的东西。

相反,您可以使用TypeOfIs

If TypeOf MyObject Is Integer Then
    intMyInteger = DirectCast(MyObject, Integer)
Else
    intMyInteger = 0
End If

这个测试用来检查MyObject运行时类型是否为Integer。欲知详情请参见TypeOf运算符的MSDN文档

你也可以像这样写:

Dim myInt As Integer = If(TypeOf myObj Is Integer, DirectCast(myObj,Integer), 0)

此外,如果一个带有默认值(比如0)的整数类型不适合,你可以考虑使用 Nullable(Of Integer) 类型。


4
我们还不知道那个对象的具体类型,我们只知道 MyObject 是一个 Object 引用,它仍然可以指向任何类型的对象。If TypeOf x Is type 表达式 用于测试对象在运行时的类型。 - Jonathon Reinhart
4
小写字母没有意义。Iif 是一个函数,已被 VB 2008 中的 If 运算符所取代。快速查看 MSDN 文档会有很大帮助。(我正在回答你的问题,但并不了解 Visual Basic。) - Jonathon Reinhart
1
除了从字符串“1”转换为整数1不是强制转换,它是一种转换(字符串被解析)。OP特别询问将他假定为整数的对象引用强制转换为整数值。我会感激那些回复点数,谢谢。 - Jonathon Reinhart
1
@CJ7 - 在这里使用IIf失败(如果myObj不是整数,则会导致异常)。 IIf始终评估真和假表达式,然后返回适当的表达式。 If(..)的重点在于它仅评估一个表达式或另一个表达式。 在这种情况下,除非我们已经验证了我们有一个整数,否则它不执行DirectCast。 在现代VB中,没有任何情况可以使用IIf(..)是有益的; 所有使用它的地方都应该用If(..)替换。 - ToolmakerSteve
@JonathonReinhart - 关于“小写字母,它们无所谓”的问题。请注意,VB是不区分大小写的。因此,iifIIf完全相同。由VB编译器根据需要转换大小写并匹配函数名称与现有函数签名。但您是正确的,IIf(..)已经没有任何好处了,已被If(..)取代 :) - ToolmakerSteve
显示剩余7条评论

5
您可以使用以下内容:
Dim intMyInteger as Integer

Integer.TryParse(MyObject, intMyInteger)

4
不,这是对OP所问问题的一个不同答案,而且两年前已经成功回答了。首先,观察到Integer.TryParse()不接受对象作为其第一个参数,只能用于字符串。这应该是你意识到OP的关于强制转换的问题与解析不同的第一个线索。 - ToolmakerSteve
字符串继承自对象,这个答案是正确的。这是对原帖问题的另一个答案,该问题已经成功解决了2年。这个选项有一个好处,如果对象包含一个以字符串格式表示的整数值,则原来的答案将无法工作,但这个答案会。另一方面,我的答案需要装箱和拆箱,这是一个缺点。 - CoOl

3

使用 Directcast 并捕获 InvalidCastException 异常。


乍一看,我认为这不是一个好的选择,因为在 .Net 中异常非常昂贵。然而,OP 确实声明他期望 Object 内部是一个 Integer;如果确实总是(或几乎总是)是一个 Integer,那么使用 DirectCast 就是完全合理的,只需要捕获(罕见的)异常即可。尽管个人上我使用 Jonathan 的风格,由于多年的 .Net 使用经验,我已经训练自己避免异常,因为它们“太昂贵”了,即使在它们并不必要的情况下也是如此。 - ToolmakerSteve

1

TryCast的等效方法是CType。如果可能,两者都会进行类型转换。相比之下,DirectCast仅在该类型已经存在时才会转换类型。

举个例子,您可以使用CType将字符串、短整型或双精度浮点数转换为整型。如果您尝试使用DirectCast进行此操作,通常会出现语法/编译错误;但是,如果您尝试通过使用类型Object(这称为“装箱”和“拆箱”)绕过错误,则会在运行时引发异常。

    Dim OnePointTwo As Object = "1.2"
    Try
        Dim temp = CType(OnePointTwo, Integer)
        Console.WriteLine("CType converted to: " & temp.ToString & " (type: " & temp.GetType.ToString & ")")
    Catch ex As Exception
        Console.WriteLine("CType threw exception")
    End Try
    Try
        Dim temp = DirectCast(OnePointTwo, Integer)
        Console.WriteLine("DirectCast converted to: " & temp.ToString & " (type: " & temp.GetType.ToString & ")")
    Catch ex As Exception
        Console.WriteLine("DirectCast threw exception")
    End Try

这将输出:
    CType converted to: 1 (type: System.Int32)
    DirectCast threw exception

为了最接近TryCast的语义,我建议使用这样的函数:

Shared Function TryCastInteger(value As Object) As Integer?
    Try
        If IsNumeric(value) Then
            Return CType(value, Integer)
        Else
            Return Nothing
        End If
    Catch ex As Exception
        Return Nothing
    End Try
End Function

并且为了说明它的效果:

Shared Sub TestTryCastInteger()
    Dim temp As Integer?

    Dim OnePointTwo As Object = "1.2"
    temp = TryCastInteger(OnePointTwo)
    If temp Is Nothing Then
        Console.WriteLine("Could not convert to Integer")
    Else
        Console.WriteLine("TryCastInteger converted to: " & temp.ToString & " (type: " & temp.GetType.ToString & ")")
    End If

    Dim NotANumber As Object = "bob's your uncle"
    temp = TryCastInteger(NotANumber)
    If temp Is Nothing Then
        Console.WriteLine("Could not convert to Integer")
    Else
        Console.WriteLine("TryCastInteger converted to: " & temp.ToString & " (type: " & temp.GetType.ToString & ")")
    End If
End Sub

运行TestTryCastInteger()将输出:

    TryCastInteger converted to: 1 (type: System.Int32)
    Could not convert to Integer

还有一种叫做可空类型的 null/Nothing 整数或任何其他静态类型,详情请参见 变量声明问号。但这并不意味着它是“引用”类型。


4
-1 对于“与 TryCast 等效的是 CType”。其实并不是这样。使用 TryCast 的整个目的是为了避免在运行时生成异常的可能性。如果转换失败,CType 引发异常。此外,TryCast 不会尝试 CType 尝试的所有转换范围。它们的使用方式非常不同。TryCast 是一种非常严格(而且快速)的转换:它尝试“向上转换”到特定的子类。当需要将实例作为更通用的基类传递时使用它。CType 可以进行更多的转换——这既可以是好事也可以是坏事... - ToolmakerSteve
根据程序员的意图,它可能会尝试更昂贵的转换,例如解析字符串。它的行为也可以在自定义类中进行重载,以执行任何操作。但即使如此,在推荐它时存在问题,因为您对OP的想法了解不足。这是一个冒险的建议,可能会导致微妙的错误。除非程序员根本不关心输入和结果是什么,只是“想让它工作”,否则不应将其用于从“Object”进行转换。这是旧的、不可靠的Basic编程方式。 - ToolmakerSteve
总之,如果一个人的目标是编写可靠的程序,那么乔纳森是正确的。如果一个人无法控制传入类型,并且被困在“Object”声明中,而你又期望一个“value”类型,那么安全的方法是开始测试对象的类型。一旦知道了对象的类型,再决定该做什么。 - ToolmakerSteve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接