如何安全地缩短长度到int?

时间:2014-11-05 18:55:44

标签: c# vb.net c#-4.0 unchecked-conversion

根据问题" Can I convert long to int?",C#将long转换为int的最佳方法是:

int myIntValue = unchecked((int)myLongValue);

如何在VB.NET中执行此操作?根据我的理解,VB.NET没有未经检查的概念。

当我在转换器中转换代码时,它说要使用CInt()。但是CInt抛出了一个system.overflowexception。在C#中使用unchecked会阻止system.overflowexception。

我宁愿不抓住例外。

Dim x As Long = Int32.MaxValue
x = x + 100
Console.WriteLine(x)

Dim y As Integer = CInt(x)
Console.WriteLine(y)

6 个答案:

答案 0 :(得分:7)

正如您在related, similar question的答案中所看到的,有很多方法可以做到这一点,但没有什么比简单的Try/Catch块更方便。如果你想避免Try/Catch块的低效率,我建议先检查一下这个值,如下所示:

If (myLongValue >= Integer.MinValue) AndAlso (myLongValue <= Integer.MaxValue) Then
    myIntValue = CInt(myLongValue)
End If

或者,如果您想将值设置为超出范围的特定值:

If myLongValue < Integer.MinValue Then
    myIntValue = Integer.MinValue
ElseIf myLongValue > Integer.MaxValue Then
    myIntValue = Integer.MaxValue
Else
    myIntValue = CInt(myLongValue)
End If

如果你想让它更方便,你可以把它变成一个功能。如果方便是最终目标,您甚至可以将其作为一种扩展方法:

<Extension>
Public Function AsInt32(value As Long) As Integer
    If value < Integer.MinValue Then
        Return Integer.MinValue
    ElseIf value > Integer.MaxValue Then
        Return Integer.MaxValue
    Else
        Return CInt(value)
    End If
End Function

答案 1 :(得分:1)

  

是否已经编写了转换函数,用于检查其是否大于,如果不是,则将其设置为Int32.MaxValue

不,但这很简单:

Dim l as Long = Int32.MaxValue + 12433243243

Dim i as Int32
if l > int32.MaxValue Then
   i = int32.MaxValue
elseIf l < int32.MinValue
   i = int32.MinValue
Else
   i = CInt(l)
End If

或者在一行中:

i = if(l > int32.MaxValue, int32.MaxValue, if(l < int32.MinValue, int32.MinValue, CInt(l)))

或使用Math.Min

i = CInt(Math.Max(Math.Min(l, int32.MaxValue), int32.MinValue))

答案 2 :(得分:1)

这是将一个long转换为int的一种相当轻松的方法,只需提取低位32位而不抛出异常。没有64位除法,没有try / catch块,只是一点点的比较和单一的比较。

Private Function CastLongToInt(x As Long) As Integer
    Dim value As Integer = CType(x And &H7FFFFFFFL, Integer) ' get the low order 31 bits

    ' If bit 32 (the sign bit for a 32-bit signed integer is set, we OR it in
    If (0 <> (x And &H80000000L)) Then
        value = value Or &H80000000I
    End If

    Return value
End Function

这是一个更简单的演绎 - 只是有点笨拙。根本没有比较。我们只需抓取2个16位半字节并将它们组合成最终值:

Private Function CastLongToInt(x As Long) As Integer
    Dim hiNibble As Integer = &HFFFFL And (x >> 16) 
    Dim loNibble As Integer = &HFFFFL And x
    Dim value As Integer = (hiNibble << 16) Or loNibble
    Return value
End Function

编辑注意:

另一种选择是使用可以为空的整数(System.Nullable<int>)。在VB.Net中,它将是这样的:

Private Function TryCastLongToInt(x As Long) As Integer?
    Dim value As Integer?
    Try
        value = CType(x, Integer)
    Catch
      ' This exception intentionall swallowed here
    End Try
    Return value
End Function

或者,如果故意捕捉和吞咽异常的概念会让你感到困惑:

Private Function TryCastLongToInt(x As Long) As Integer?
    If (x < Integer.MinValue) Then Return Nothing
    If (x > Integer.MaxValue) Then Return Nothing
    Return x
End Function

无论哪种方式,如果64位值超出32位整数的域,返回值将是整数值或Nothing

答案 3 :(得分:0)

您可以在Convert.ToInt32中使用mod函数:

i = Convert.ToInt32(x Mod (Int32.MaxValue))

答案 4 :(得分:0)

执行此类操作的无分支方式是:

Function UInt64ToInt32Wrap(v As UInt64) As Int32
    Return CInt((CUInt(v And &HFFFFFFFFUI) Xor &H80000000UI) + &H80000000)
End Function
Function Int64ToInt32Wrap(v As Int64) As Int32
    Return CInt(((v And &HFFFFFFFFL) Xor &H80000000L) + &H80000000)
End Function
Function UInt32ToInt32Wrap(v As UInt32) As Int32
    Return CInt((v Xor &H80000000UI) + &H80000000)
End Function

请注意,在每种情况下,最后一个十六进制值都是Int32,其值为-2147483648,因此将其添加到无符号类型将导致促销Int64;将其添加到前一个XOR的结果将始终产生一个Int32范围内的值。

我希望其中一个作为编译器内部提供,因为即使操作是无分支的,JIT也可能将所有内容都减少为32位“xor”和32位“add”指令,没有必要使用 ANY 代码来实现这一目标。

顺便提一下,我认为另一种方法是定义一个覆盖Int32UInt32的“LayoutKind.Explicit”属性的结构;这可能会消除不必要的相互取消算术运算,但它可能会强制抖动将值存储到内存中并重新加载它,否则它会将内容保存在寄存器中。

答案 5 :(得分:0)

到目前为止,很棒的答案,这里是另一个与Steven Doggart相似的人:

Dim x As Long = Int32.MaxValue
x = x + 100
Console.WriteLine(x)

Dim y As Integer
If x > Int32.MaxValue Then y = Int32.MaxValue Else y = x
Console.WriteLine(y)

结果:

2147483747
2147483647

或者:

Dim x As Long = Long.MaxValue
Console.WriteLine(x)

Dim y As Integer
If x > Int32.MaxValue Then y = Int32.MaxValue Else y = x
Console.WriteLine(y)

结果:

9223372036854775807
2147483647

将其包裹在一个函数中:

Function DownsizeLongToInt(ByVal x As Long) As Integer
    Dim y As Integer
    If x > Int32.MaxValue Then y = Int32.MaxValue Else y = x
    Return y
End Function

注意功能名称。我已经用这种方式命名,这表明这会导致截断/数据丢失,并且不应该用于&#34;转换&#34; long to Int,这可能是有损的,也可能是各种转换函数不尝试这样做的原因。只是一个猜测。