4

「 long を int に変換できますか? 」という質問によると、C# で long を int に変換する最良の方法は次のとおりです。

int myIntValue = unchecked((int)myLongValue);

VB.NET でこれを行うにはどうすればよいですか? 私の理解では、VB.NET には unchecked という概念がありません。

コンバーターでコードを変換すると、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)
4

6 に答える 6

7

私の関連する同様の質問への回答でわかるように、そのようなことを行う方法はありますが、単純な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
于 2014-11-05T19:07:52.843 に答える
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))
于 2014-11-05T19:07:44.813 に答える
1

これは、long を int にダウン キャストするかなり簡単な方法で、例外をスローせずに下位 32 ビットを抽出するだけです。64 ビットの除算も、try/catch ブロックもありません。ビットをいじるだけで、比較は 1 回だけです。

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

注意するように編集:

もう 1 つのオプションは、null 許容整数 ( 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

どちらの方法でも、戻り値は整数値になるかNothing、64 ビット値が 32 ビット整数のドメイン外にある場合に返されます。

于 2014-11-05T20:17:44.373 に答える
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

関数名に注意してください。これが切り捨て/データ損失を引き起こす可能性があり、Long を Int に「変換」するために使用すべきではないことを示すために、そのように名前を付けました。関数はこれを試みません。推測です。

于 2014-11-05T21:05:48.853 に答える
0

Convert.ToInt32 で mod 関数を使用できます。

i = Convert.ToInt32(x Mod (Int32.MaxValue))
于 2014-11-05T19:10:34.837 に答える
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

いずれの場合も、最後の 16 進数値はInt32値が -2147483648 であるため、符号なしの型に追加すると昇格が発生することに注意してくださいInt64。それを前の XOR の結果に追加すると、常に の範囲内の値が得られますInt32

これらのいずれかがコンパイラ組み込み関数として提供されていればよかったのですが、操作はブランチレスであり、JIT はおそらくすべてを 32 ビットの "xor" 命令と 32 ビットの "add" 命令に減らすことができますが、そうすべきではありません。それを達成するために任意のコードを使用する必要はありません。

Int32ちなみに、別のアプローチは、 anと a UInt32;をオーバーレイする「LayoutKind.Explicit」属性を使用して構造を定義することだと思います。これにより、不必要な相互キャンセル算術演算が不要になる可能性がありますが、ジッターが値をメモリに格納し、それ以外の場合はレジスタに保持できる場合に再ロードする可能性があります。

于 2014-11-05T19:30:39.703 に答える