VB のたまご

作成日: 2015/12/03, 更新日: 2015/12/03


InvalidOperationException について

概要

  •  InvalidOperationException は、誤った命令の使い方をした時に発生します。 正しい命令の使い方を知ることが、解決の糸口につながります。


スポンサーリンク


事例と対処方法

  •  以下のサンプルは、意図的に例外エラーを発生させるコードです。 実際の業務プログラムでは、このような簡単なコードではないと思いますが、例外発生させている、直接的な原因となる部分として参考になるはずです。 また、本例外エラーが発生してしまう原因となった、根本的な原因となる別の例外エラーが、さらに奥深くにいる場合があります。 (本例外エラーは間接的に影響を受けて発生してしまったもので、本当の原因となる例外エラーを食い止めることで、本例外エラーも直る場合があります。)

  •  このような組み合わせのパターンは、本例外エラーに限らず、他の例外エラー全般にも言えることですが、そんなに頻繁に出くわすものではないと思いますので、 そういう場合もあるということだけ、覚えておいていただけると解決しやすくなるのではと思います。

  •  また、記載の対処方法は、あくまでも一例です。 他の対処方法の方が、その業務プログラムにとってベストプラクティスとなる場合もありますので、検討材料の1つという程度に確認していただければと思います。

  • スポンサーリンク



  • ArrayList
  • ' ループ中のコレクションデータを削除する
    Dim lst As New ArrayList(New Integer() {1, 2, 3})
    For Each oneData In lst
        lst.Remove(oneData)
    Next
    
    ' 例外エラー
    System.InvalidOperationException: コレクションが変更されました。列挙操作は実行されない可能性があります。
       場所 System.Collections.ArrayList.ArrayListEnumeratorSimple.MoveNext()
    
    ' 対処方法
    ループ中のコレクションデータに対して、追加、削除、挿入の操作は実施しない。
    または、
    Dim lst As New ArrayList(New Integer() {1, 2, 3})
    Dim workList = lst.ToArray().ToList()
    For Each oneData In workList
        lst.Remove(oneData)
    Next
    
  •  For Each ループでは、IEnumerable、IEnumerator インターフェースの機能を利用した列挙処理を利用しています。 詳細はこちら。ループ中にコレクションデータの状態が変わってしまうと、この列挙処理がうまく実施されません。 For ループの場合は、ArgumentOutOfRangeException という別の例外エラーが発生する場合があります。 どちらにしても、ループ中のコレクションデータに対して、編集操作は避けるべきと考えます。
  •  代案としては、別のコレクションデータを準備して利用することで、編集処理が実施できます。


  • List(Of Integer)
  • ' ループ中のコレクションデータを削除する
    Dim lst As New List(Of Integer)(New Integer() {1, 2, 3})
    For Each oneData In lst
        lst.Remove(oneData)
    Next
    
    ' 例外エラー
    System.InvalidOperationException: コレクションが変更されました。列挙操作は実行されない可能性があります。
       場所 System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
       場所 System.Collections.Generic.List`1.Enumerator.MoveNextRare()
       場所 System.Collections.Generic.List`1.Enumerator.MoveNext()
    
    ' 対処方法
    ループ中のコレクションデータに対して、追加、削除、挿入の操作は実施しない。
    または、
    Dim lst As New List(Of Integer)(New Integer() {1, 2, 3})
    Dim workList = lst.ToList()
    For Each oneData In workList
        lst.Remove(oneData)
    Next
    
  •  ArrayList の事例と同様です。


  • 別スレッドからのコントロールアクセス、その1
  • Public Class Form1
    
        ' 画面上に、Button と BackgroudWorker を貼っています
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Me.Button1.Text = "hello"
        End Sub
    End Class
    
    ' 例外エラー
    型 'System.InvalidOperationException' の例外が System.Windows.Forms.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした
    
    追加情報:有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'xxx' がアクセスされました。
    
    ' 対処方法
    ' バックグラウンドスレッドからコントロールを操作する時は、 Invoke メソッド経由でコントロールを操作します。
    Private Sub bk_DoWork(sender As Object, e As DoWorkEventArgs) Handles bk.DoWork
        Me.Invoke(Sub() Me.btn.Text = "hello")
    End Sub
    
  •  VB.NET では、バックグラウンドスレッド等の別スレッド上から、UI スレッド管理下にあるコントロールを操作しようとすると、危険な操作という扱いを受けます。 この仕様は、マルチスレッドプログラミング、同期処理・非同期処理を勉強すると、分かるようになります。 この例外エラーが発生したということは、そのメソッドは別スレッド上で動作している、ということなので、 Invoke メソッド経由でコントロールにアクセスすることで、正しい操作となり例外エラーを回避できます。


  • 別スレッドからのコントロールアクセス、その2
  • Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Task.Run(Sub() Me.Button1.Text = "hello")
    End Sub
    
    ' 例外エラー
    型 'System.InvalidOperationException' の例外が System.Windows.Forms.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした
    
    追加情報:有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'xxx' がアクセスされました。
    
    ' 対処方法
    ' バックグラウンドスレッドからコントロールを操作する時は、 Invoke メソッド経由でコントロールを操作します。
    Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Task.Run(Sub() Me.Invoke(Sub() Me.Button1.Text = "hello"))
    End Sub
    
  •  BackgroundWorkder コンポーネントと同様です。

  •  最後までこの記事を読んでいただき、ありがとうございました。

  • スポンサーリンク