Поделиться через


Класс System.InvalidCastException

В этой статье приводятся дополнительные замечания к справочной документации по этому API.

.NET поддерживает автоматическое преобразование производных типов в базовые типы и обратно в производный тип, а также от типов, которые представляют интерфейсы для объектов интерфейса и обратно. Он также включает различные механизмы, поддерживающие пользовательские преобразования. Дополнительные сведения см. в разделе "Преобразование типов" в .NET.

Исключение InvalidCastException возникает, когда преобразование экземпляра одного типа в другой тип не поддерживается. Например, при попытке преобразовать Char значение в DateTime значение вызывается InvalidCastException исключение. Он отличается от OverflowException исключения, которое возникает при поддержке преобразования одного типа в другой, но значение исходного типа выходит за пределы диапазона целевого типа. Исключение InvalidCastException вызвано ошибкой разработчика и не должно обрабатываться в блоке try/catch . Вместо этого следует устранить причину исключения.

Сведения о преобразованиях, поддерживаемых системой, см. в Convert классе. Ошибки, возникающие при хранении значений исходного типа, но недостаточно больших для хранения определенного исходного значения, см OverflowException . исключение.

Примечание.

Во многих случаях компилятор языка обнаруживает, что преобразование между исходным типом и целевым типом не существует и выдает ошибку компилятора.

Некоторые условия, при которых попытка преобразования вызывает InvalidCastException исключение, рассматриваются в следующих разделах.

Чтобы явное преобразование ссылок было успешно выполнено, исходное значение должно быть nullравно, или тип объекта, на который ссылается исходный аргумент, должен быть преобразован в тип назначения путем неявного преобразования ссылок.

Следующие инструкции промежуточного InvalidCastException языка (IL) вызывают исключение:

  • castclass
  • refanyval
  • unbox

InvalidCastException использует HRESULT COR_E_INVALIDCAST, который имеет значение 0x80004002.

Список начальных значений свойств для экземпляра 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# или CType метод преобразования в Visual Basic (если Option Strict он включен).

Однако если ни исходный тип, ни целевой тип не определяют явное или сужающее преобразование между двумя типами, а 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 объект или если объект являетсяnull.Person

Преобразование из объекта интерфейса

Вы пытаетесь преобразовать объект интерфейса в тип, реализующий этот интерфейс, но целевой тип не совпадает с типом или базовым классом типа, от которого объект интерфейса был первоначально производным. В следующем примере возникает 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))