System.InvalidCastException 类

本文提供了此 API 参考文档的补充说明。

.NET 支持从派生类型到其基类型并转换回派生类型的自动转换,以及从呈现接口的类型到接口对象并转换回呈现接口的类型的自动转换。 它还包括支持自定义转换的各种机制。 有关详细信息,请参阅 .NET 中的类型转换

当不支持将一种类型的实例转换为另一种类型时,会引发 InvalidCastException 异常。 例如,尝试将 Char 值转换为 DateTime 值会引发 InvalidCastException 异常。 该异常不同于 OverflowException 异常,后者是在支持将一种类型转换为另一种类型时引发的,但源类型的值超出了目标类型的范围。 InvalidCastException 异常是由开发人员错误引起的,不应在 try/catch 块中处理。 而是应消除异常的原因。

有关系统支持的转换的信息,请参阅 Convert 类。 有关当目标类型可以存储源类型值但不足以存储特定源值时发生的错误,请参阅 OverflowException 异常。

注意

在许多情况下,你的语言编译器会检测到源类型和目标类型之间不存在转换,并发出编译器错误。

以下各节将讨论尝试转换引发 InvalidCastException 异常的一些条件。

为了使显式引用转换成功,源值必须为 null,或者源参数引用的对象类型必须可通过隐式引用转换转换为目标类型。

以下中间语言 (IL) 指令引发异常 InvalidCastException

  • castclass
  • refanyval
  • unbox

InvalidCastException 使用 HRESULT COR_E_INVALIDCAST,后者的值为 0x80004002。

有关实例的初始属性值的列表InvalidCastException,请参阅InvalidCastException构造函数。

基元类型和 IConvertible

直接或间接调用不支持特定转换的基元类型的 IConvertible 实现。 例如,尝试将 Boolean 值转换为 Char 或将 DateTime 值转换为 Int32 将引发 InvalidCastException 异常。 以下示例调用 Boolean.IConvertible.ToCharConvert.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 为 ON)是执行转换所必需的。

但是,如果源类型和目标类型都未定义这两种类型之间的显式转换或收缩转换,并且一种或两种类型的 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))