System.InvalidCastException 类

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

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

当不支持将一个类型的实例转换为另一个类型时,将抛出异常。 例如,尝试将 Char 值转换为 DateTime 值时,会抛出 InvalidCastException 异常。 它不同于OverflowException异常,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.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对象时,向下转换才会成功。

从接口对象转换

您正在尝试将接口对象转换为实现该接口的类型,但目标类型既不是与接口对象最初派生的相同类型,也不是该类型的基类。 以下示例在尝试将InvalidCastException对象转换为对象IFormatProvider时引发DateTimeFormatInfo异常。 转换失败,因为虽然 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))