Code Fix

上級

ArrayTypeMismatchException の原因と直し方

配列の共変性(string[]をobject[]として扱えること)を利用したコードで、実体の型と異なる要素を代入すると発生します。

エラーメッセージの読み方

Unhandled exception. System.ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array.
System
名前空間 — System なら標準の基本例外です
ArrayTypeMismatchException
例外クラス — 何が起きたか。ここを検索するのが最短です
Attempted to access an element as a type incompatible with the array.
詳細メッセージ — どの値が問題だったか
at Program.Main(String[] args) in Program.cs:line 5
発生箇所 — スタックトレースの先頭行

このエラーが出る典型パターン

パターン1

 1  class Program {
 2      static void Main(string[] args) {
 3          string[] strs = new string[3];
 4          object[] objs = strs;
 5          objs[0] = 123 ;
                        ^
 6          System.Console.WriteLine(objs[0]);
 7      }
 8  }
Unhandled exception. System.ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array. at Program.Main(String[] args) in Program.cs:line 5

配列は共変性を持つため、string[]をobject[]として扱えてしまいます。しかし実体は変わらずstring配列なので、string以外を入れると実行時に例外になります。

直し方: 123 を "hi" にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  class Person { public string Name; }
 2  class Program {
 3      static void Main(string[] args) {
 4          Person[] people = new Person[2];
 5          object[] objs = people;
 6          objs[0] = "Al"                      ;
                                   ^
 7          System.Console.WriteLine(objs[0]);
 8      }
 9  }
Unhandled exception. System.ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array. at Program.Main(String[] args) in Program.cs:line 6

Person型の配列でも同じことが起きます。参照型どうしでも、配列の実体(ここではPerson[])と違う型を入れると実行時に検出されます。

直し方: "Al" を new Person { Name = "Al" } にします。

この問題を解いてみる →

パターン3

 1  class Program {
 2      static void Main(string[] args) {
 3          string[] names = new string[2];
 4          object[] objs = names;
 5          objs[1] = true ;
                        ^
 6          System.Console.WriteLine(objs[1]);
 7      }
 8  }
Unhandled exception. System.ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array. at Program.Main(String[] args) in Program.cs:line 5

boolのような値型を入れても同じ例外になります。配列の実体の型(ここではstring[])だけが正解を決めます。

直し方: true を "bob" にします。

この問題を解いてみる →

パターン4

 1  class Book { public string Title; }
 2  class Program {
 3      static void Main(string[] args) {
 4          Book[] books = new Book[2];
 5          object[] objs = books;
 6          objs[0] = 123                     ;
                                  ^
 7          System.Console.WriteLine(objs[0]);
 8      }
 9  }
Unhandled exception. System.ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array. at Program.Main(String[] args) in Program.cs:line 6

Book[]をobject[]として扱っても実体はBook[]のままなので、Book以外を入れると実行時に例外になります。

直し方: 123 を new Book { Title = "T" } にします。

この問題を解いてみる →

パターン5

 1  class Program {
 2      static void Main(string[] args) {
 3          string[] words = new string[2];
 4          object[] objs = words;
 5          objs[0] = true;
                        ^
 6          System.Console.WriteLine(objs[0]);
 7      }
 8  }
Unhandled exception. System.ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array. at Program.Main(String[] args) in Program.cs:line 5

boolのような値型を代入しても、配列の実体の型と一致しないため例外になります。

直し方: true を "hi" にします。

この問題を解いてみる →

よくある誤解

コンパイラはobject[]への代入を許してしまうため、コンパイル時には気づけません。配列の「見た目の型」と「実体の型」が違うことが原因です。

実務での勘所

配列の共変性は、実はC#独自の欠陥ではなくJavaにも同じ形で存在する、意図的に受け継がれた設計です。ジェネリクスが存在しなかった時代、Array.Sortのような「あらゆる参照型の配列に使える」汎用的なメソッドを書く手段が配列の共変性しか無かったため、型安全性より汎用性を優先してこの設計が採用されました。ジェネリクスが使えるようになった現在では、List<T>のようなジェネリックコレクションを使えばこの種の型安全性の穴を避けられるため、新しいコードで配列の共変性に頼る場面は少なくなっています。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)