次の方法で共有


System.InvalidCastException クラス

この記事では、この API のリファレンス ドキュメントに補足的な解説を提供します。

.NET では、派生型から基本型への自動変換、派生型への変換、およびインターフェイス オブジェクトとインターフェイス オブジェクトへのインターフェイスを提供する型からの自動変換がサポートされています。 また、カスタム変換をサポートするさまざまなメカニズムも含まれています。 詳細については、「.NET での型変換」を参照してください。

InvalidCastException例外は、ある型のインスタンスから別の型への変換がサポートされていない場合にスローされます。 たとえば、 Char 値を DateTime 値に変換しようとすると、 InvalidCastException 例外がスローされます。 OverflowException例外とは異なります。これは、ある型から別の型への変換がサポートされているが、ソース型の値がターゲット型の範囲外である場合にスローされます。 InvalidCastException例外は開発者エラーによって発生し、try/catch ブロックでは処理しないでください。 代わりに、例外の原因を排除する必要があります。

システムでサポートされる変換の詳細については、 Convert クラスを参照してください。 変換先の型がソース型の値を格納できるが、特定のソース値を格納するのに十分な大きさではない場合に発生するエラーについては、 OverflowException 例外を参照してください。

多くの場合、言語コンパイラは、ソース型とターゲット型の間に変換が存在しないことを検出し、コンパイラ エラーを発行します。

変換の試行によって InvalidCastException 例外がスローされる条件の一部については、次のセクションで説明します。

明示的な参照変換を成功させるには、ソース値を nullするか、ソース引数によって参照されるオブジェクト型を暗黙的な参照変換によって変換先の型に変換できる必要があります。

次の中間言語 (IL) 命令では、 InvalidCastException 例外がスローされます。

  • castclass
  • refanyval
  • unbox

InvalidCastException は、値が0x80004002を持つ HRESULT COR_E_INVALIDCASTを使用します。

InvalidCastExceptionのインスタンスの初期プロパティ値の一覧については、InvalidCastExceptionコンストラクターを参照してください。

プリミティブ型と IConvertible

特定の変換をサポートしていないプリミティブ型の IConvertible 実装を直接または間接的に呼び出します。 たとえば、 Boolean 値を Char に変換したり、 DateTime 値を Int32 に変換しようとすると、 InvalidCastException 例外がスローされます。 次の例では、 Boolean.IConvertible.ToChar メソッドと Convert.ToChar(Boolean) メソッドの両方を呼び出して、 Boolean 値を Charに変換します。 どちらの場合も、メソッド呼び出しは InvalidCastException 例外をスローします。

using System;

public class IConvertibleEx
{
    public static void Main()
    {
        bool flag = true;
        try
        {
            IConvertible conv = flag;
            Char ch = conv.ToChar(null);
            Console.WriteLine("Conversion succeeded.");
        }
        catch (InvalidCastException)
        {
            Console.WriteLine("Cannot convert a Boolean to a Char.");
        }

        try
        {
            Char ch = Convert.ToChar(flag);
            Console.WriteLine("Conversion succeeded.");
        }
        catch (InvalidCastException)
        {
            Console.WriteLine("Cannot convert a Boolean to a Char.");
        }
    }
}
// The example displays the following output:
//       Cannot convert a Boolean to a Char.
//       Cannot convert a Boolean to a Char.
open System

let flag = true
try
    let conv: IConvertible = flag
    let ch = conv.ToChar null
    printfn "Conversion succeeded."
with :? InvalidCastException ->
    printfn "Cannot convert a Boolean to a Char."

try
    let ch = Convert.ToChar flag
    printfn "Conversion succeeded."
with :? InvalidCastException ->
    printfn "Cannot convert a Boolean to a Char."

// The example displays the following output:
//       Cannot convert a Boolean to a Char.
//       Cannot convert a Boolean to a Char.
Module Example2
    Public Sub Main()
        Dim flag As Boolean = True
        Try
            Dim conv As IConvertible = flag
            Dim ch As Char = conv.ToChar(Nothing)
            Console.WriteLine("Conversion succeeded.")
        Catch e As InvalidCastException
            Console.WriteLine("Cannot convert a Boolean to a Char.")
        End Try

        Try
            Dim ch As Char = Convert.ToChar(flag)
            Console.WriteLine("Conversion succeeded.")
        Catch e As InvalidCastException
            Console.WriteLine("Cannot convert a Boolean to a Char.")
        End Try
    End Sub
End Module
' The example displays the following output:
'       Cannot convert a Boolean to a Char.
'       Cannot convert a Boolean to a Char.

変換はサポートされていないため、回避策はありません。

Convert.ChangeType メソッド

Convert.ChangeType メソッドを呼び出してオブジェクトをある型から別の型に変換しましたが、一方または両方の型でIConvertible インターフェイスが実装されていません。

ほとんどの場合、変換はサポートされていないため、回避策はありません。 場合によっては、考えられる回避策として、ソース型のプロパティ値をターゲット型の同様のプロパティに手動で割り当てることがあります。

縮小変換と IConvertible 実装

縮小演算子は、型でサポートされる明示的な変換を定義します。 変換を実行するには、C# のキャスト演算子または Visual Basic の CType 変換メソッド ( Option Strict がオンの場合) が必要です。

ただし、ソース型とターゲット型のどちらも、2 つの型間の明示的または縮小変換を定義せず、一方または両方の型の IConvertible 実装でソース型からターゲット型への変換がサポートされていない場合は、 InvalidCastException 例外がスローされます。

ほとんどの場合、変換はサポートされていないため、回避策はありません。

ダウンキャスト

ダウンキャストしています。つまり、基本型のインスタンスを派生型のいずれかに変換しようとしています。 次の例では、 Person オブジェクトを PersonWithID オブジェクトに変換しようとすると失敗します。

using System;

public class Person
{
   String _name;

   public String Name
   {
      get { return _name; }
      set { _name = value; }
   }
}

public class PersonWithId : Person
{
   String _id;

   public string Id
   {
      get { return _id; }
      set { _id = value; }
   }
}

public class Example
{
   public static void Main()
   {
      Person p = new Person();
      p.Name = "John";
      try {
         PersonWithId pid = (PersonWithId) p;
         Console.WriteLine("Conversion succeeded.");
      }
      catch (InvalidCastException) {
         Console.WriteLine("Conversion failed.");
      }

      PersonWithId pid1 = new PersonWithId();
      pid1.Name = "John";
      pid1.Id = "246";
      Person p1 = pid1;
      try {
         PersonWithId pid1a = (PersonWithId) p1;
         Console.WriteLine("Conversion succeeded.");
      }
      catch (InvalidCastException) {
         Console.WriteLine("Conversion failed.");
      }

      Person p2 = null;
      try {
         PersonWithId pid2 = (PersonWithId) p2;
         Console.WriteLine("Conversion succeeded.");
      }
      catch (InvalidCastException) {
         Console.WriteLine("Conversion failed.");
      }
   }
}
// The example displays the following output:
//       Conversion failed.
//       Conversion succeeded.
//       Conversion succeeded.
open System

type Person() =
    member val Name = String.Empty with get, set

type PersonWithId() =
    inherit Person()
    member val Id = String.Empty with get, set


let p = Person()
p.Name <- "John"
try
    let pid = p :?> PersonWithId
    printfn "Conversion succeeded."
with :? InvalidCastException ->
    printfn "Conversion failed."

let pid1 = PersonWithId()
pid1.Name <- "John"
pid1.Id <- "246"
let p1: Person = pid1
try
    let pid1a = p1 :?> PersonWithId
    printfn "Conversion succeeded."
with :? InvalidCastException ->
    printfn "Conversion failed."

// The example displays the following output:
//       Conversion failed.
//       Conversion succeeded.
Public Class Person
   Dim _name As String
   
   Public Property Name As String
      Get
         Return _name
      End Get
      Set
         _name = value
      End Set
   End Property
End Class

Public Class PersonWithID : Inherits Person
   Dim _id As String
   
   Public Property Id As String
      Get
         Return _id
      End Get
      Set
         _id = value
      End Set
   End Property
End Class

Module Example1
    Public Sub Main()
        Dim p As New Person()
        p.Name = "John"
        Try
            Dim pid As PersonWithID = CType(p, PersonWithID)
            Console.WriteLine("Conversion succeeded.")
        Catch e As InvalidCastException
            Console.WriteLine("Conversion failed.")
        End Try

        Dim pid1 As New PersonWithID()
        pid1.Name = "John"
        pid1.Id = "246"
        Dim p1 As Person = pid1

        Try
            Dim pid1a As PersonWithID = CType(p1, PersonWithID)
            Console.WriteLine("Conversion succeeded.")
        Catch e As InvalidCastException
            Console.WriteLine("Conversion failed.")
        End Try

        Dim p2 As Person = Nothing
        Try
            Dim pid2 As PersonWithID = CType(p2, PersonWithID)
            Console.WriteLine("Conversion succeeded.")
        Catch e As InvalidCastException
            Console.WriteLine("Conversion failed.")
        End Try
    End Sub
End Module
' The example displays the following output:
'       Conversion failed.
'       Conversion succeeded.
'       Conversion succeeded.

この例に示すように、ダウンキャストは、 Person オブジェクトが PersonWithId オブジェクトから Person オブジェクトへのアップキャストによって作成された場合、または Person オブジェクトが nullされている場合にのみ成功します。

インターフェイス オブジェクトからの変換

インターフェイス オブジェクトを、そのインターフェイスを実装する型に変換しようとしていますが、ターゲットの型が、インターフェイス オブジェクトの派生元の型と同じ型または基底クラスではありません。 次の例では、IFormatProvider オブジェクトをDateTimeFormatInfo オブジェクトに変換しようとすると、InvalidCastException例外がスローされます。 DateTimeFormatInfo クラスはIFormatProvider インターフェイスを実装していますが、DateTimeFormatInfo オブジェクトはインターフェイス オブジェクトの派生元のCultureInfo クラスに関連付けされていないため、変換は失敗します。

using System;
using System.Globalization;

public class InterfaceEx
{
    public static void Main()
    {
        var culture = CultureInfo.InvariantCulture;
        IFormatProvider provider = culture;

        DateTimeFormatInfo dt = (DateTimeFormatInfo)provider;
    }
}
// The example displays the following output:
//    Unhandled Exception: System.InvalidCastException:
//       Unable to cast object of type //System.Globalization.CultureInfo// to
//           type //System.Globalization.DateTimeFormatInfo//.
//       at Example.Main()
open System
open System.Globalization

let culture = CultureInfo.InvariantCulture
let provider: IFormatProvider = culture

let dt = provider :?> DateTimeFormatInfo

// The example displays the following output:
//    Unhandled Exception: System.InvalidCastException:
//       Unable to cast object of type //System.Globalization.CultureInfo// to
//           type //System.Globalization.DateTimeFormatInfo//.
//       at Example.main()
Imports System.Globalization

Module Example3
    Public Sub Main()
        Dim culture As CultureInfo = CultureInfo.InvariantCulture
        Dim provider As IFormatProvider = culture

        Dim dt As DateTimeFormatInfo = CType(provider, DateTimeFormatInfo)
    End Sub
End Module
' The example displays the following output:
'    Unhandled Exception: System.InvalidCastException: 
'       Unable to cast object of type 'System.Globalization.CultureInfo' to 
'           type 'System.Globalization.DateTimeFormatInfo'.
'       at Example.Main()

例外メッセージが示すように、インターフェイス オブジェクトが元の型のインスタンス (この場合は CultureInfo) に変換された場合にのみ、変換は成功します。 インターフェイス オブジェクトが元の型の基本型のインスタンスに変換された場合も、変換は成功します。

文字列変換

C# でキャスト演算子を使用して、値またはオブジェクトを文字列形式に変換しようとしています。 次の例では、 Char 値を文字列にキャストしようとしても、整数を文字列にキャストしようとすると、 InvalidCastException 例外がスローされます。

public class StringEx
{
    public static void Main()
    {
        object value = 12;
        // Cast throws an InvalidCastException exception.
        string s = (string)value;
    }
}
let value: obj = 12
// Cast throws an InvalidCastException exception.
let s = value :?> string

Visual Basic CStr 演算子を使用してプリミティブ型の値を文字列に変換すると成功します。 この操作では、 InvalidCastException 例外はスローされません。

任意の型のインスタンスを文字列形式に正常に変換するには、次の例のように、 ToString メソッドを呼び出します。 ToString メソッドは常に存在します。ToString メソッドはObject クラスによって定義されるため、すべてのマネージド型によって継承またはオーバーライドされます。

using System;

public class ToStringEx2
{
    public static void Main()
    {
        object value = 12;
        string s = value.ToString();
        Console.WriteLine(s);
    }
}
// The example displays the following output:
//      12
let value: obj = 12
let s = value.ToString()
printfn $"{s}"
// The example displays the following output:
//      12

Visual Basic 6.0 の移行

ユーザー コントロールのカスタム イベントを呼び出して Visual Basic 6.0 アプリケーションを Visual Basic .NET にアップグレードすると、"指定されたキャストが無効です" というメッセージで InvalidCastException 例外がスローされます。この例外を排除するには、フォームのコード行 ( Form1 など) を変更します。

Call UserControl11_MyCustomEvent(UserControl11, New UserControl1.MyCustomEventEventArgs(5))

次のコード行に置き換えます。

Call UserControl11_MyCustomEvent(UserControl11(0), New UserControl1.MyCustomEventEventArgs(5))