1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

初心者向けよくあるエラーとその対処法(C#,VB.Net)

Posted at

紹介

業務でVisual Studio2022を利用して、Webアプリ(VB.Net)を開発しています(歴3年)。また、C#での開発も勉強中です。あの時知っていれば、と思ったエラーと対処法の共有です。

これを知ることで、自分のコードでエラーが起きた際、正しく対処できるはずです。

前提 & 環境

Visual Studio 2022を利用して、C#とVB.Netのサンプルコードを書きました。
初学者向けに、コードを簡単に書いている部分も一部あります。
VB.Netでは、実行でエラーとなるが、C#では、コンパイラでエラーとなるコードもあるため、完全に一致していないサンプルコードもあります。


Windows 11 home
Visual Studio Community 2022 17.14.3
C# .netFramework 4.7.2
VB.Net Framework 4.7.2

内容

エラーを英語で書いていますが、日本語でも説明をするので、
安心してください。

  • NullReferenceException
  • IndexOutOfRangeException
  • InvalidCastException
  • FormatException
  • まとめ
1.NullReferenceException

1.NullReferenceException

一言でいうと「中身がないものを使おうとして失敗したエラー」です。
サンプルコードで、確認をしてみましょう。

C#

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ErrorProgram
{
    internal class Program
    {
        static void Main(string[] args)
        {
            
            string sampleString = null;

            int sampleLength = sampleString.Length;


        }
    }
}

VB.Net

Option Strict Off
Module Module1

    Sub Main()

        Dim sampleString As String

        Dim sampleLength As Integer = sampleString.Length

    End Sub

End Module

このコードを実行した際のメッセージを確認してみましょう。
C#
image.png

VB.Net
image.png

同様のメッセージですよね(nullとNothingで表現は違いますが)。
どちらも「中身がないものを使おうとして失敗したエラー」という形になります。
プログラマーには、Nullが好きな方はいないと思います。
こんな簡単なミスはしないぞと思う方もいると思いますが、
コードを長く書いたり、複雑なものだったり、共同で作業を行ったりすると起こしてしまいます。
C#の方は、意図的に変数にNullを仕込みました。
また、VB.Netの方は構文ミスです。

対処法のプログラムを書いてみます。

C# 対処法1
Nullが入る可能性のある場合は、Nullでないかを判定する。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ErrorProgram
{
    internal class Program
    {
        static void Main(string[] args)
        {

            string sampleString = null;

            //nullでないか判定
            if (sampleString != null)
            {
                int sampleLength = sampleString.Length;

            }
                
            
            

        }
    }
}

C# 対処法2
Nullを扱わない。
Null→""とする。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ErrorProgram
{
    internal class Program
    {
        static void Main(string[] args)
        {

            string sampleString = "";

            int sampleLength = sampleString.Length;
            
            
            //int sampleInt;

            //sampleInt = sampleInt + 1;

        }
    }
}

上記の方法が挙げられます。
*付け加えると、C#8.0では、プロジェクト単位、ファイル単位でのNullの禁止が行えるようになっています。新規かつNullを使わないのであれば、そちらの設定を行うとよいかと思います。

VBの方も挙げます。

VB.Net Nullでないかを判定する。

説明 Option Strict On
暗黙の型変換を許さない。必ず、型変換を行うこと!
Nullが入る可能性のある場合

Option Strict On
Module Module1

    Sub Main()

        Dim sampleString As String

        'Nullでないか判定する
        If Not IsNothing(sampleString) Then
            Dim sampleLength As Integer = sampleString.Length
        End If

    End Sub

End Module

VB.Netの場合、初期値を入れる。
変数 As String = ""とする。

Option Strict On
Module Module1

    Sub Main()

        Dim sampleString As String = ""

        'Nullでないか判定する
        If Not IsNothing(sampleString) Then
            Dim sampleLength As Integer = sampleString.Length
        End If

    End Sub

End Module

VB.Netの頭につけているOption Strict Onについて
VB.Netは型変換が緩いため、つけておくべき規則です。勝手にStringをIntegerに入れようとすると、コンパイラがエラーを起こしてくれます。
「本番コードでは Option Strict On を推奨」します。
実行前に気づける点が利点です!

コメント

変数にNullが、入るかもしれないことを想定しましょう!

2.IndexOutOfRangeException

次のエラーです。
一言でいうと、「存在しない番号にアクセスしたエラー」です。
どちらも配列を利用していますが、実行時にエラーとなります。
C#とVB.Netで異なるプログラムを書いています。

C#の場合
配列の範囲外の値を指定

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ErrorProgram
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int[] oneDimArray = new int[3]{ 1, 2 ,3};
            
            int thirdValue = 0;

            thirdValue = oneDimArray[3];

            

        }
    }
}

VBの場合、
For文を使用
Lengthの値まで(0,1,2,3まで)増えていっています。

Option Strict Off
Module Module1

    Sub Main()

        '配列
        Dim oneDimArray() As Integer = {1, 2, 3}

        '合計
        Dim sum As Integer = 0

        For i = 0 To oneDimArray.Length

            sum = sum + oneDimArray(i)

        Next

    End Sub

End Module

C#もVB.Netも配列の要素は、0から始まっていきます。
なので、1から数えた値を入れたり、Length - 1を入れないと、
エラーが起きてしまいます。

実際に動かしてみるデバッグの時でないと、気づかなかったりするので注意が必要です。
実行時のエラー

C#の場合
image.png

VB.Netの場合
image.png

それぞれのプログラムを直してみました。
最後の値を取り出したい場合は、要素数 - 1と書くことで、取り出せます。
C#の場合

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ErrorProgram
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int[] oneDimArray = new int[3] { 1, 2, 3 };

            int thirdValue = 0;

            thirdValue = oneDimArray[oneDimArray.Length - 1];



        }
    }
}

*下のVB.Netの例のようにFor Eachを利用することが、C#でも可能です。

VB.Netの場合
誤りの可能性があるFor文を使わずにFor Each文を利用して
配列の要素を1つずつ取り出すことで、対応しています。

Option Strict Off
Module Module1

    Sub Main()

        '配列
        Dim oneDimArray() As Integer = {1, 2, 3}

        '合計
        Dim sum As Integer = 0

        For Each value As Integer In oneDimArray

            sum = sum + value

        Next

    End Sub

End Module

コメント2

配列といったまとまりを扱う場合は、範囲外の値を使わないように、気をつけましょう。

3.InvalidCastException

続いてのエラーは、
無効な型変換
「変えられない型に無理やり変えようとしたエラー」
例)文字列を数値に変えようとしたけど、できなかった。
といったケースです。

C#の場合
Object型の値を無理やり数値型に変更しようとしているため、エラーが起きます。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ErrorProgram
{
    internal class Program
    {
        static void Main(string[] args)
        {
            object sampleObject = "123";


            int intSample = (int)sampleObject + 1;


        }
    }
}

VB.Netの場合です。
C#と同様に、型変換でエラーが起きています。

Option Strict On
Module Module1

    Sub Main()

        Dim value As Object = "123"
        Dim number As Integer = DirectCast(value, Integer) + 1


    End Sub

End Module

実際に実行してみましょう。
C#の場合
image.png

VB.Netの場合
image.png

といった具合で、Object型から、いきなり変換しようとしてはいけません。
こういった場合、値が入っていない(Nullの場合)も考慮して、下記のように書きます。

C#の場合
!= を利用して、nullでないことを確認。
&& を利用。左から1つ目の条件式が成り立たない場合、2つ目以降の式は、実行されない。
int.TryParseを使用
(1つ目の式の値をint型に変換、その結果を引数に入れる)。
int.TryParseは、型変換に失敗した場合は、False。成功した場合は、Trueを返す。
ToStringを使用(Object型の値を文字列として変換する、nullに対して行うとエラーが起きる)。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ErrorProgram
{
    internal class Program
    {
        static void Main(string[] args)
        {
            object sampleObject = "123";

            int intSample = 0;

            if (sampleObject != null && int.TryParse(sampleObject.ToString(), out intSample))
            {

                intSample = intSample + 1;
            }



        }
    }
    }

VB.Netの場合
IsNothingで、null(Nothing)出ないことを確認。
AndAlsoは、を利用。左から1つ目の条件式が成り立たない場合、2つ目以降の式は、実行されない。
Integer.TryParseを利用する。(1つ目の式の値をint型に変換、その結果を引数に入れる)。
型変換に失敗した場合は、False。成功した場合は、Trueを返す。
ToStringを使用(Object型の値を文字列として使用する。nullに対して行うと、エラーが起きる)。

Option Strict On
Module Module1

    Sub Main()


        Dim value As Object = "123"
        Dim number As Integer = 0

        If Not IsNothing(value) AndAlso Integer.TryParse(value.ToString(), number) Then

            number = number + 1

        End If


    End Sub

End Module

コメント3

指定した変数の型で変換できない場合を想定しましょう。

4.FormatException

一言でいうと、指定外の書式エラー
先に挙げたInvalidCastExceptionと紛らわしいですが、
こちらは、値自体が変換できないものだった場合に起きます。
例)そもそも変換できない文字列を整数にしようとした」

C#の例です。
ABCという文字列を整数に変換しようとしています。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ErrorProgram
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string hoge = "ABC";

            int hogeInt = int.Parse(hoge);
        }
    }
}

VB.Netの場合、
C#と同様に、ABCDEという文字列を整数に変換しようとしています。

Option Strict Off
Module Module1

    Sub Main()


        Dim hoge As String = "ABCDE"

        Dim hogeInt As Integer = Integer.Parse(hoge)


    End Sub

End Module

それぞれの実行結果を見てみます。

C#の場合、
image.png

VB.Netの場合、
image.png

これらのプログラムのエラー対策は、先に挙げたInvalidCastExceptionのプログラムと同様です。

修正例
C#の場合
InvalidCastExceptionとも一部重なりますが、
hoge != null はnull出ないことを確認
&& を利用。左から1つ目の条件式が成り立たない場合、2つ目以降の式は、実行されない。
TryParseで変換(1つ目の式で、string型の値をint型に変換。2つ目の式に結果の値を入れる)。
型変換に失敗した場合は、False。成功した場合は、Trueを返す。

文字列型 stringなので、ToString()は使う必要がないといった形です。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ErrorProgram
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string hoge = "ABC";

            int hogeInt = 0;

            if (hoge != null && int.TryParse(hoge, out hogeInt))
            {
                //hogeIntへの処理
            }

        }
    }
}

VB.Netの場合
Not IsNothing(hoge)はNullでないことを確認
AndAlso を利用。左から1つ目の条件式が成り立たない場合、2つ目以降の式は、実行されない。
TryParseで変換(1つ目の式で、String型の値をint型に変換。2つ目の式に結果の値を入れる)。
型変換に失敗した場合は、False。成功した場合は、Trueを返す。

文字列型 Stringなので、ToString()は使う必要がないといった形です。

Option Strict On
Module Module1

    Sub Main()


        Dim hoge As String = "ABCDE"

        Dim hogeInt As Integer = 0

        If Not IsNothing(hoge) AndAlso Integer.TryParse(hoge, hogeInt) Then

            'hogeIntの処理

        End If

    End Sub

End Module

コメント4

ユーザー入力は、変換に失敗する可能性あることも、想定しておきましょう!

といった具合です。
お疲れ様です。

5.まとめ

まとめ表

例外(Exception) 原因 防ぎ方
NullReference Nullに触れた Nullかをチェック or 非Null値を入れる
IndexOutOfRange 範囲外に出た Length-1 or foreach
InvalidCast 無効な変換 TryParse,TryCast
Format 形式が問題あり TryParse

コードと見比べてみた結果は、どうでしょうか?
エラーは、プログラムの実行の失敗を伝えてくれる。
バグは、プログラマーが埋め込んでしまう失敗です。

業務を行う上では、バグを避けるため、慎重に扱いましょう。
例え、エラーだったとしても見逃してしまったら、
それはバグとなってしまいます。

VB.NetやC#を利用している方々の少しでも助けになればと思います。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?