For Eachは縮小変換されるのか?最終鬼畜言語VB.NET

はじめに

なんか結構このタイトルが使いやすいのでこれから積極的に使おうかなと思っております今日この頃です。

我らが啓典msdnを眺めていたところ、For Eachについて気になる記述がありました。

For Each...Next ステートメント (Visual Basic)

Option Strict が On に設定されている場合、縮小変換は通常はコンパイラ エラーの原因になります。 ただし、For Each ステートメントでは、group 内の要素から element への変換は、実行時に評価されて実行され、縮小変換を原因とするコンパイラ エラーは抑制されます。

MA☆ZI☆DE!!

検証

とりあえずコードを書いて実行してみましょう。

Option Strict On

Module Module1

    Sub Main()
        Dim longArray = New Long() {1L, 10L, 100L, Long.MaxValue}

        Try
            For Each it As Integer In longArray
                Console.WriteLine(it)
            Next
        Catch ex As OverflowException
            Console.WriteLine("オーバーフロー発生の秘密だにゃん")
        End Try

        Dim hogeArray = New HogeB() {
            New HogeB(1L), New HogeB(10L),
            New HogeB(100L), New HogeB(Long.MaxValue)}

        Try
            For Each it As HogeA In hogeArray
                it.Display()
            Next
        Catch ex As OverflowException
            Console.WriteLine("オーバーフロー発生の秘密だにゃん")
        End Try
    End Sub

End Module


Class HogeA
    Private value As Integer

    Public Sub New(value As Integer)
        Me.value = value
    End Sub

    Public Sub Display()
        Console.WriteLine(value)
    End Sub

    Public Shared Widening Operator CType(source As HogeA) As HogeB
        Return New HogeB(source.value)
    End Operator
End Class

Class HogeB
    Private value As Long

    Public Sub New(value As Long)
        Me.value = value
    End Sub

    Public Sub Display()
        Console.WriteLine(value)
    End Sub

    Public Shared Narrowing Operator CType(source As HogeB) As HogeA
        Dim v = CType(source.value, Integer)
        Return New HogeA(v)
    End Operator
End Class
1
10
100
オーバーフロー発生の秘密だにゃん
1
10
100
オーバーフロー発生の秘密だにゃん

Option Strict Onが指定されているのにも関わらず暗黙の縮小変換を含むコードのコンパイルが成功してしまいます。 そして、期待通り実行時に例外がスローされています。

それじゃあC#はどうなのさと。

class Program
{
    static void Main(string[] args)
    {
        long[] longArray = { 1, 10, 100, long.MaxValue };

        try
        {
            foreach (int it in longArray)
            {
                Console.WriteLine(it);
            }
        }
        catch (OverflowException)
        {
            Console.WriteLine("あぁ^~例外がぴょんぴょんするんじゃぁ^~");
        }

        HogeB[] hogeArray = 
        {new HogeB(1), new HogeB(10), new HogeB(100), new HogeB(long.MaxValue) };

        try
        {
            foreach (HogeA it in hogeArray)
            {
                it.Display();
            }
        }
        catch (OverflowException)
        {
            Console.WriteLine("あぁ^~例外がぴょんぴょんするんじゃぁ^~");
        }

        Console.ReadLine();
    }
}

class HogeA
{
    private int _value;

    public HogeA(int value)
    {
        this._value = value;
    }

    public void Display()
    {
        Console.WriteLine(_value);
    }

    public static implicit operator HogeB(HogeA hoge)
    {
        return new HogeB(hoge._value);
    }
}

class HogeB
{
    private long _value;

    public HogeB(long value)
    {
        this._value = value;
    }

    public void Display()
    {
        Console.WriteLine(_value);
    }

    public static explicit operator HogeA(HogeB hoge)
    {
        return new HogeA((int)hoge._value);
    }
}
1
10
100
あぁ^~例外がぴょんぴょんするんじゃぁ^~
1
10
100
あぁ^~例外がぴょんぴょんするんじゃぁ^~

あらあら。 C#でもforeachステートメントでは暗黙的に縮小変換してもコンパイルは成功して実行時に例外がスローされます。

For Eachで暗黙的な縮小変換が許されちゃうのはVBだけかと思ったのですがC#も許されちゃうんですね。

大抵はループ内でくるくる回す変数は型推論で定義しちゃうと思うのですが、なんらかのクソの様なコーディングガイドラインのせいで明示的に型を宣言するときは注意が必要ですね。 っていう無難な決め台詞で締めます。よくわかんないし

おわり