Exception Clase
Definición
Importante
Parte de la información hace referencia a la versión preliminar del producto, que puede haberse modificado sustancialmente antes de lanzar la versión definitiva. Microsoft no otorga ninguna garantía, explícita o implícita, con respecto a la información proporcionada aquí.
Representa los errores que se producen durante la ejecución de la aplicación.
public ref class Exception
public ref class Exception : System::Runtime::Serialization::ISerializable
public ref class Exception : System::Runtime::InteropServices::_Exception, System::Runtime::Serialization::ISerializable
public class Exception
public class Exception : System.Runtime.Serialization.ISerializable
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDual)]
[System.Serializable]
public class Exception : System.Runtime.Serialization.ISerializable
[System.Serializable]
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)]
[System.Runtime.InteropServices.ComVisible(true)]
public class Exception : System.Runtime.InteropServices._Exception, System.Runtime.Serialization.ISerializable
[System.Serializable]
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)]
[System.Runtime.InteropServices.ComVisible(true)]
public class Exception : System.Runtime.Serialization.ISerializable
type Exception = class
type Exception = class
interface ISerializable
[<System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDual)>]
[<System.Serializable>]
type Exception = class
interface ISerializable
[<System.Serializable>]
[<System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type Exception = class
interface ISerializable
interface _Exception
[<System.Serializable>]
[<System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type Exception = class
interface ISerializable
Public Class Exception
Public Class Exception
Implements ISerializable
Public Class Exception
Implements _Exception, ISerializable
- Herencia
-
Exception
- Derivado
- Atributos
- Implementaciones
Ejemplos
En el ejemplo siguiente se muestra un catch
bloque (with
en F#) que se define para controlar ArithmeticException los errores. Este catch
bloque también detecta DivideByZeroException errores, ya que DivideByZeroException se deriva de ArithmeticException y no hay ningún catch
bloque definido explícitamente para DivideByZeroException los errores.
using namespace System;
int main()
{
int x = 0;
try
{
int y = 100 / x;
}
catch ( ArithmeticException^ e )
{
Console::WriteLine( "ArithmeticException Handler: {0}", e );
}
catch ( Exception^ e )
{
Console::WriteLine( "Generic Exception Handler: {0}", e );
}
}
/*
This code example produces the following results:
ArithmeticException Handler: System.DivideByZeroException: Attempted to divide by zero.
at main()
*/
using System;
class ExceptionTestClass
{
public static void Main()
{
int x = 0;
try
{
int y = 100 / x;
}
catch (ArithmeticException e)
{
Console.WriteLine($"ArithmeticException Handler: {e}");
}
catch (Exception e)
{
Console.WriteLine($"Generic Exception Handler: {e}");
}
}
}
/*
This code example produces the following results:
ArithmeticException Handler: System.DivideByZeroException: Attempted to divide by zero.
at ExceptionTestClass.Main()
*/
module ExceptionTestModule
open System
let x = 0
try
let y = 100 / x
()
with
| :? ArithmeticException as e ->
printfn $"ArithmeticException Handler: {e}"
| e ->
printfn $"Generic Exception Handler: {e}"
// This code example produces the following results:
// ArithmeticException Handler: System.DivideByZeroException: Attempted to divide by zero.
// at <StartupCode$fs>.$ExceptionTestModule.main@()
Class ExceptionTestClass
Public Shared Sub Main()
Dim x As Integer = 0
Try
Dim y As Integer = 100 / x
Catch e As ArithmeticException
Console.WriteLine("ArithmeticException Handler: {0}", e.ToString())
Catch e As Exception
Console.WriteLine("Generic Exception Handler: {0}", e.ToString())
End Try
End Sub
End Class
'
'This code example produces the following results:
'
'ArithmeticException Handler: System.OverflowException: Arithmetic operation resulted in an overflow.
' at ExceptionTestClass.Main()
'
Comentarios
Esta clase es la clase base para todas las excepciones. Cuando se produce un error, el sistema o la aplicación que se ejecuta actualmente lo notifican iniciando una excepción que contiene información sobre el error. Una vez que se produce una excepción, la aplicación o el controlador de excepciones predeterminado lo controla.
En esta sección:
Errores y excepciones
Bloques try/catch
Características del tipo de excepción
Propiedades de la clase exception
Consideraciones de rendimiento
Volver a iniciar una excepción
Elección de excepciones estándar
Implementación de excepciones personalizadas
Errores y excepciones
Los errores en tiempo de ejecución pueden producirse por diversos motivos. Sin embargo, no todos los errores se deben controlar como excepciones en el código. Estas son algunas categorías de errores que pueden producirse en tiempo de ejecución y las formas adecuadas de responder a ellos.
Errores de uso. Un error de uso representa un error en la lógica del programa que puede dar lugar a una excepción. Sin embargo, el error debe solucionarse no mediante el control de excepciones, sino modificando el código defectuoso. Por ejemplo, la invalidación del Object.Equals(Object) método en el ejemplo siguiente supone que el
obj
argumento siempre debe ser distinto de NULL.using System; public class Person { private string _name; public string Name { get { return _name; } set { _name = value; } } public override int GetHashCode() { return this.Name.GetHashCode(); } public override bool Equals(object obj) { // This implementation contains an error in program logic: // It assumes that the obj argument is not null. Person p = (Person) obj; return this.Name.Equals(p.Name); } } public class Example { public static void Main() { Person p1 = new Person(); p1.Name = "John"; Person p2 = null; // The following throws a NullReferenceException. Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)); } }
// In F#, null is not a valid state for declared types // without 'AllowNullLiteralAttribute' [<AllowNullLiteral>] type Person() = member val Name = "" with get, set override this.GetHashCode() = this.Name.GetHashCode() override this.Equals(obj) = // This implementation contains an error in program logic: // It assumes that the obj argument is not null. let p = obj :?> Person this.Name.Equals p.Name let p1 = Person() p1.Name <- "John" let p2: Person = null // The following throws a NullReferenceException. printfn $"p1 = p2: {p1.Equals p2}"
Public Class Person Private _name As String Public Property Name As String Get Return _name End Get Set _name = value End Set End Property Public Overrides Function Equals(obj As Object) As Boolean ' This implementation contains an error in program logic: ' It assumes that the obj argument is not null. Dim p As Person = CType(obj, Person) Return Me.Name.Equals(p.Name) End Function End Class Module Example Public Sub Main() Dim p1 As New Person() p1.Name = "John" Dim p2 As Person = Nothing ' The following throws a NullReferenceException. Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)) End Sub End Module
La NullReferenceException excepción que da como resultado cuando
obj
senull
puede eliminar modificando el código fuente para probar explícitamente el valor NULL antes de llamar a la Object.Equals invalidación y, a continuación, volver a compilar. El ejemplo siguiente contiene el código fuente corregido que controla unnull
argumento.using System; public class Person { private string _name; public string Name { get { return _name; } set { _name = value; } } public override int GetHashCode() { return this.Name.GetHashCode(); } public override bool Equals(object obj) { // This implementation handles a null obj argument. Person p = obj as Person; if (p == null) return false; else return this.Name.Equals(p.Name); } } public class Example { public static void Main() { Person p1 = new Person(); p1.Name = "John"; Person p2 = null; Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)); } } // The example displays the following output: // p1 = p2: False
// In F#, null is not a valid state for declared types // without 'AllowNullLiteralAttribute' [<AllowNullLiteral>] type Person() = member val Name = "" with get, set override this.GetHashCode() = this.Name.GetHashCode() override this.Equals(obj) = // This implementation handles a null obj argument. match obj with | :? Person as p -> this.Name.Equals p.Name | _ -> false let p1 = Person() p1.Name <- "John" let p2: Person = null printfn $"p1 = p2: {p1.Equals p2}" // The example displays the following output: // p1 = p2: False
Public Class Person Private _name As String Public Property Name As String Get Return _name End Get Set _name = value End Set End Property Public Overrides Function Equals(obj As Object) As Boolean ' This implementation handles a null obj argument. Dim p As Person = TryCast(obj, Person) If p Is Nothing Then Return False Else Return Me.Name.Equals(p.Name) End If End Function End Class Module Example Public Sub Main() Dim p1 As New Person() p1.Name = "John" Dim p2 As Person = Nothing Console.WriteLine("p1 = p2: {0}", p1.Equals(p2)) End Sub End Module ' The example displays the following output: ' p1 = p2: False
En lugar de usar el control de excepciones para los errores de uso, puede usar el Debug.Assert método para identificar errores de uso en compilaciones de depuración y el Trace.Assert método para identificar errores de uso en compilaciones de depuración y versión. Para obtener más información, vea Aserciones en el código administrado.
Errores del programa. Un error de programa es un error en tiempo de ejecución que no se puede evitar necesariamente escribiendo código sin errores.
En algunos casos, un error del programa puede reflejar una condición de error esperada o rutinaria. En este caso, es posible que desee evitar el uso del control de excepciones para tratar el error del programa y, en su lugar, reintentar la operación. Por ejemplo, si se espera que el usuario escriba una fecha en un formato determinado, puede analizar la cadena de fecha llamando al DateTime.TryParseExact método , que devuelve un Boolean valor que indica si la operación de análisis se realizó correctamente, en lugar de usar el DateTime.ParseExact método , que produce una FormatException excepción si la cadena de fecha no se puede convertir en un DateTime valor. Del mismo modo, si un usuario intenta abrir un archivo que no existe, primero puede llamar al File.Exists método para comprobar si el archivo existe y, si no lo hace, preguntar al usuario si desea crearlo.
En otros casos, un error de programa refleja una condición de error inesperada que se puede controlar en el código. Por ejemplo, incluso si ha comprobado que existe un archivo, se puede eliminar antes de abrirlo o puede estar dañado. En ese caso, intentar abrir el archivo mediante la creación de instancias de un StreamReader objeto o la llamada al Open método puede producir una FileNotFoundException excepción. En estos casos, debe usar el control de excepciones para recuperarse del error.
Errores del sistema. Un error del sistema es un error en tiempo de ejecución que no se puede controlar mediante programación de forma significativa. Por ejemplo, cualquier método puede producir una OutOfMemoryException excepción si Common Language Runtime no puede asignar memoria adicional. Normalmente, los errores del sistema no se controlan mediante el control de excepciones. En su lugar, puede usar un evento como AppDomain.UnhandledException y llamar al Environment.FailFast método para registrar la información de excepción y notificar al usuario el error antes de que finalice la aplicación.
Bloques try/catch
Common Language Runtime proporciona un modelo de control de excepciones basado en la representación de excepciones como objetos y la separación del código de programa y el código de control de excepciones en try
bloques y catch
bloques. Puede haber uno o varios catch
bloques, cada uno diseñado para controlar un tipo determinado de excepción o un bloque diseñado para detectar una excepción más específica que otro bloque.
Si una aplicación controla las excepciones que se producen durante la ejecución de un bloque de código de aplicación, el código debe colocarse dentro de una try
instrucción y se denomina try
bloque . El código de aplicación que controla las excepciones producidas por un try
bloque se coloca dentro de una catch
instrucción y se denomina catch
bloque . Cero o más catch
bloques están asociados a un try
bloque y cada catch
bloque incluye un filtro de tipo que determina los tipos de excepciones que controla.
Cuando se produce una excepción en un try
bloque, el sistema busca en los bloques asociados catch
en el orden en que aparecen en el código de la aplicación, hasta que localiza un catch
bloque que controla la excepción. Un catch
bloque controla una excepción de tipo T
si el filtro de tipo del bloque catch especifica T
o cualquier tipo derivado T
de . El sistema deja de buscar después de encontrar el primer catch
bloque que controla la excepción. Por este motivo, en el código de la aplicación, se debe especificar un catch
bloque que controle un tipo antes de un catch
bloque que controle sus tipos base, como se muestra en el ejemplo siguiente a esta sección. Último bloque catch que controla System.Exception
.
Si ninguno de los catch
bloques asociados al bloque actual try
controla la excepción y el bloque actual try
se anida dentro de otros try
bloques de la llamada actual, se buscan los catch
bloques asociados al siguiente bloque envolvente try
. Si no se encuentra ningún catch
bloque para la excepción, el sistema busca niveles de anidamiento anteriores en la llamada actual. Si no se encuentra ningún catch
bloque para la excepción en la llamada actual, la excepción se pasa a la pila de llamadas y se busca en el marco de pila anterior un catch
bloque que controla la excepción. La búsqueda de la pila de llamadas continúa hasta que se controla la excepción o hasta que no existen más marcos en la pila de llamadas. Si se alcanza la parte superior de la pila de llamadas sin encontrar un catch
bloque que controle la excepción, el controlador de excepciones predeterminado lo controla y la aplicación finaliza.
F# try.. with Expression
F# no usa catch
bloques. En su lugar, una excepción generada coincide con el patrón mediante un único with
bloque. Como se trata de una expresión, en lugar de una instrucción , todas las rutas de acceso deben devolver el mismo tipo. Para obtener más información, consulte El intento... con expresión.
Características del tipo de excepción
Los tipos de excepciones admiten las siguientes características:
Texto legible que describe el error. Cuando se produce una excepción, el tiempo de ejecución hace que un mensaje de texto esté disponible para informar al usuario de la naturaleza del error y sugerir una acción para resolver el problema. Este mensaje de texto se mantiene en la Message propiedad del objeto de excepción. Durante la creación del objeto de excepción, puede pasar una cadena de texto al constructor para describir los detalles de esa excepción concreta. Si no se proporciona ningún argumento de mensaje de error al constructor, se usa el mensaje de error predeterminado. Para obtener más información, vea la propiedad Message.
Estado de la pila de llamadas cuando se produjo la excepción. La StackTrace propiedad lleva un seguimiento de pila que se puede usar para determinar dónde se produce el error en el código. El seguimiento de la pila enumera todos los métodos llamados y los números de línea del archivo de origen donde se realizan las llamadas.
Propiedades de la clase exception
La Exception clase incluye una serie de propiedades que ayudan a identificar la ubicación del código, el tipo, el archivo de ayuda y el motivo de la excepción: StackTrace, InnerException, Message, HelpLinkHResult, Source, , TargetSitey Data.
Cuando existe una relación causal entre dos o más excepciones, la InnerException propiedad mantiene esta información. La excepción externa se produce en respuesta a esta excepción interna. El código que controla la excepción externa puede usar la información de la excepción interna anterior para controlar el error de forma más adecuada. La información complementaria sobre la excepción se puede almacenar como una colección de pares clave-valor en la Data propiedad .
La cadena de mensaje de error que se pasa al constructor durante la creación del objeto de excepción debe localizarse y se puede proporcionar desde un archivo de recursos mediante la ResourceManager clase . Para obtener más información sobre los recursos localizados, vea los temas Creación de ensamblados satélite y empaquetado e implementación de recursos .
Para proporcionar al usuario información extensa sobre por qué se produjo la excepción, la HelpLink propiedad puede contener una dirección URL (o URN) en un archivo de ayuda.
La Exception clase usa el COR_E_EXCEPTION HRESULT, que tiene el valor 0x80131500.
Para obtener una lista de los valores de propiedad iniciales de una instancia de la Exception clase , vea los Exception constructores.
Consideraciones de rendimiento
La iniciación o control de una excepción consume una cantidad significativa de recursos del sistema y tiempo de ejecución. Inicie excepciones solo para controlar condiciones verdaderamente extraordinarias, no para controlar eventos predecibles o control de flujo. Por ejemplo, en algunos casos, como cuando se desarrolla una biblioteca de clases, es razonable iniciar una excepción si un argumento de método no es válido, ya que se espera que se llame al método con parámetros válidos. Un argumento de método no válido, si no es el resultado de un error de uso, significa que se ha producido algo extraordinario. Por el contrario, no inicie una excepción si la entrada del usuario no es válida, ya que puede esperar que los usuarios escriban ocasionalmente datos no válidos. En su lugar, proporcione un mecanismo de reintento para que los usuarios puedan escribir una entrada válida. Tampoco debe usar excepciones para controlar los errores de uso. En su lugar, use aserciones para identificar y corregir errores de uso.
Además, no inicie una excepción cuando un código de retorno sea suficiente; no convierta un código de retorno en una excepción; y no detectan rutinariamente una excepción, lo omiten y, a continuación, continúan procesando.
Inicio repetido de una excepción
En muchos casos, un controlador de excepciones simplemente quiere pasar la excepción al autor de la llamada. Esto suele ocurrir en:
Una biblioteca de clases que, a su vez, encapsula las llamadas a métodos de la biblioteca de clases de .NET Framework u otras bibliotecas de clases.
Una aplicación o biblioteca que encuentra una excepción grave. El controlador de excepciones puede registrar la excepción y, a continuación, volver a iniciar la excepción.
La manera recomendada de volver a iniciar una excepción es simplemente usar la instrucción throw en C#, la función reraise en F#, y la instrucción Throw en Visual Basic sin incluir una expresión. Esto garantiza que toda la información de la pila de llamadas se conserve cuando la excepción se propague al autor de la llamada. Esto se ilustra en el siguiente ejemplo: Un método de extensión de cadena, FindOccurrences
, ajusta una o varias llamadas a String.IndexOf(String, Int32) sin validar sus argumentos de antemano.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public static class Library
{
public static int[] FindOccurrences(this String s, String f)
{
var indexes = new List<int>();
int currentIndex = 0;
try {
while (currentIndex >= 0 && currentIndex < s.Length) {
currentIndex = s.IndexOf(f, currentIndex);
if (currentIndex >= 0) {
indexes.Add(currentIndex);
currentIndex++;
}
}
}
catch (ArgumentNullException e) {
// Perform some action here, such as logging this exception.
throw;
}
return indexes.ToArray();
}
}
open System
module Library =
let findOccurrences (s: string) (f: string) =
let indexes = ResizeArray()
let mutable currentIndex = 0
try
while currentIndex >= 0 && currentIndex < s.Length do
currentIndex <- s.IndexOf(f, currentIndex)
if currentIndex >= 0 then
indexes.Add currentIndex
currentIndex <- currentIndex + 1
with :? ArgumentNullException ->
// Perform some action here, such as logging this exception.
reraise ()
indexes.ToArray()
Imports System.Collections.Generic
Imports System.Runtime.CompilerServices
Public Module Library
<Extension()>
Public Function FindOccurrences(s As String, f As String) As Integer()
Dim indexes As New List(Of Integer)
Dim currentIndex As Integer = 0
Try
Do While currentIndex >= 0 And currentIndex < s.Length
currentIndex = s.IndexOf(f, currentIndex)
If currentIndex >= 0 Then
indexes.Add(currentIndex)
currentIndex += 1
End If
Loop
Catch e As ArgumentNullException
' Perform some action here, such as logging this exception.
Throw
End Try
Return indexes.ToArray()
End Function
End Module
A continuación, un autor de llamada llama FindOccurrences
dos veces. En la segunda llamada a FindOccurrences
, el autor de la llamada pasa como null
cadena de búsqueda, lo que hace que el String.IndexOf(String, Int32) método produzca una ArgumentNullException excepción. El método controla FindOccurrences
esta excepción y se devuelve al autor de la llamada. Dado que la instrucción throw se usa sin expresión, la salida del ejemplo muestra que se conserva la pila de llamadas.
public class Example
{
public static void Main()
{
String s = "It was a cold day when...";
int[] indexes = s.FindOccurrences("a");
ShowOccurrences(s, "a", indexes);
Console.WriteLine();
String toFind = null;
try {
indexes = s.FindOccurrences(toFind);
ShowOccurrences(s, toFind, indexes);
}
catch (ArgumentNullException e) {
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name);
Console.WriteLine("Message:\n {0}\n", e.Message);
Console.WriteLine("Stack Trace:\n {0}\n", e.StackTrace);
}
}
private static void ShowOccurrences(String s, String toFind, int[] indexes)
{
Console.Write("'{0}' occurs at the following character positions: ",
toFind);
for (int ctr = 0; ctr < indexes.Length; ctr++)
Console.Write("{0}{1}", indexes[ctr],
ctr == indexes.Length - 1 ? "" : ", ");
Console.WriteLine();
}
}
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message:
// Value cannot be null.
// Parameter name: value
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.FindOccurrences(String s, String f)
// at Example.Main()
open Library
let showOccurrences toFind (indexes: int[]) =
printf $"'{toFind}' occurs at the following character positions: "
for i = 0 to indexes.Length - 1 do
printf $"""{indexes[i]}{if i = indexes.Length - 1 then "" else ", "}"""
printfn ""
let s = "It was a cold day when..."
let indexes = findOccurrences s "a"
showOccurrences "a" indexes
printfn ""
let toFind: string = null
try
let indexes = findOccurrences s toFind
showOccurrences toFind indexes
with :? ArgumentNullException as e ->
printfn $"An exception ({e.GetType().Name}) occurred."
printfn $"Message:\n {e.Message}\n"
printfn $"Stack Trace:\n {e.StackTrace}\n"
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message:
// Value cannot be null. (Parameter 'value')
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.findOccurrences(String s, String f)
// at <StartupCode$fs>.main@()
Module Example
Public Sub Main()
Dim s As String = "It was a cold day when..."
Dim indexes() As Integer = s.FindOccurrences("a")
ShowOccurrences(s, "a", indexes)
Console.WriteLine()
Dim toFind As String = Nothing
Try
indexes = s.FindOccurrences(toFind)
ShowOccurrences(s, toFind, indexes)
Catch e As ArgumentNullException
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name)
Console.WriteLine("Message:{0} {1}{0}", vbCrLf, e.Message)
Console.WriteLine("Stack Trace:{0} {1}{0}", vbCrLf, e.StackTrace)
End Try
End Sub
Private Sub ShowOccurrences(s As String, toFind As String, indexes As Integer())
Console.Write("'{0}' occurs at the following character positions: ",
toFind)
For ctr As Integer = 0 To indexes.Length - 1
Console.Write("{0}{1}", indexes(ctr),
If(ctr = indexes.Length - 1, "", ", "))
Next
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' 'a' occurs at the following character positions: 4, 7, 15
'
' An exception (ArgumentNullException) occurred.
' Message:
' Value cannot be null.
' Parameter name: value
'
' Stack Trace:
' at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
' ngComparison comparisonType)
' at Library.FindOccurrences(String s, String f)
' at Example.Main()
Por el contrario, si se vuelve a producir la excepción mediante .
throw e;
Throw e
raise e
Instrucción , la pila de llamadas completa no se conserva y el ejemplo generaría la siguiente salida:
'a' occurs at the following character positions: 4, 7, 15
An exception (ArgumentNullException) occurred.
Message:
Value cannot be null.
Parameter name: value
Stack Trace:
at Library.FindOccurrences(String s, String f)
at Example.Main()
Una alternativa ligeramente más complicada es iniciar una nueva excepción y conservar la información de pila de llamadas de la excepción original en una excepción interna. A continuación, el autor de la llamada puede usar la nueva propiedad de InnerException la excepción para recuperar el marco de pila y otra información sobre la excepción original. En este caso, la instrucción throw es:
throw new ArgumentNullException("You must supply a search string.",
e);
raise (ArgumentNullException("You must supply a search string.", e) )
Throw New ArgumentNullException("You must supply a search string.",
e)
El código de usuario que controla la excepción debe saber que la InnerException propiedad contiene información sobre la excepción original, como se muestra en el siguiente controlador de excepciones.
try {
indexes = s.FindOccurrences(toFind);
ShowOccurrences(s, toFind, indexes);
}
catch (ArgumentNullException e) {
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name);
Console.WriteLine(" Message:\n{0}", e.Message);
Console.WriteLine(" Stack Trace:\n {0}", e.StackTrace);
Exception ie = e.InnerException;
if (ie != null) {
Console.WriteLine(" The Inner Exception:");
Console.WriteLine(" Exception Name: {0}", ie.GetType().Name);
Console.WriteLine(" Message: {0}\n", ie.Message);
Console.WriteLine(" Stack Trace:\n {0}\n", ie.StackTrace);
}
}
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message: You must supply a search string.
//
// Stack Trace:
// at Library.FindOccurrences(String s, String f)
// at Example.Main()
//
// The Inner Exception:
// Exception Name: ArgumentNullException
// Message: Value cannot be null.
// Parameter name: value
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.FindOccurrences(String s, String f)
try
let indexes = findOccurrences s toFind
showOccurrences toFind indexes
with :? ArgumentNullException as e ->
printfn $"An exception ({e.GetType().Name}) occurred."
printfn $" Message:\n{e.Message}"
printfn $" Stack Trace:\n {e.StackTrace}"
let ie = e.InnerException
if ie <> null then
printfn " The Inner Exception:"
printfn $" Exception Name: {ie.GetType().Name}"
printfn $" Message: {ie.Message}\n"
printfn $" Stack Trace:\n {ie.StackTrace}\n"
// The example displays the following output:
// 'a' occurs at the following character positions: 4, 7, 15
//
// An exception (ArgumentNullException) occurred.
// Message: You must supply a search string.
//
// Stack Trace:
// at Library.FindOccurrences(String s, String f)
// at Example.Main()
//
// The Inner Exception:
// Exception Name: ArgumentNullException
// Message: Value cannot be null.
// Parameter name: value
//
// Stack Trace:
// at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
// ngComparison comparisonType)
// at Library.FindOccurrences(String s, String f)
Try
indexes = s.FindOccurrences(toFind)
ShowOccurrences(s, toFind, indexes)
Catch e As ArgumentNullException
Console.WriteLine("An exception ({0}) occurred.",
e.GetType().Name)
Console.WriteLine(" Message: {1}{0}", vbCrLf, e.Message)
Console.WriteLine(" Stack Trace:{0} {1}{0}", vbCrLf, e.StackTrace)
Dim ie As Exception = e.InnerException
If ie IsNot Nothing Then
Console.WriteLine(" The Inner Exception:")
Console.WriteLine(" Exception Name: {0}", ie.GetType().Name)
Console.WriteLine(" Message: {1}{0}", vbCrLf, ie.Message)
Console.WriteLine(" Stack Trace:{0} {1}{0}", vbCrLf, ie.StackTrace)
End If
End Try
' The example displays the following output:
' 'a' occurs at the following character positions: 4, 7, 15
'
' An exception (ArgumentNullException) occurred.
' Message: You must supply a search string.
'
' Stack Trace:
' at Library.FindOccurrences(String s, String f)
' at Example.Main()
'
' The Inner Exception:
' Exception Name: ArgumentNullException
' Message: Value cannot be null.
' Parameter name: value
'
' Stack Trace:
' at System.String.IndexOf(String value, Int32 startIndex, Int32 count, Stri
' ngComparison comparisonType)
' at Library.FindOccurrences(String s, String f)
Elección de excepciones estándar
Cuando tenga que producir una excepción, a menudo puede usar un tipo de excepción existente en .NET Framework en lugar de implementar una excepción personalizada. Debe usar un tipo de excepción estándar en estas dos condiciones:
Está iniciando una excepción causada por un error de uso (es decir, por un error en la lógica del programa realizada por el desarrollador que llama al método). Normalmente, se produciría una excepción como ArgumentException, ArgumentNullException, InvalidOperationExceptiono NotSupportedException. La cadena que se proporciona al constructor del objeto de excepción al crear una instancia del objeto de excepción debe describir el error para que el desarrollador pueda corregirlo. Para obtener más información, vea la propiedad Message.
Está controlando un error que se puede comunicar al autor de la llamada con una excepción de .NET Framework existente. Debe iniciar la excepción más derivada posible. Por ejemplo, si un método requiere que un argumento sea un miembro válido de un tipo de enumeración, debe iniciar una InvalidEnumArgumentException (la clase más derivada) en lugar de .ArgumentException
En la tabla siguiente se enumeran los tipos de excepción comunes y las condiciones en las que se producirían.
Excepción | Condición |
---|---|
ArgumentException | Un argumento que no es NULL que se pasa a un método no es válido. |
ArgumentNullException | Un argumento que se pasa a un método es null . |
ArgumentOutOfRangeException | Un argumento está fuera del intervalo de valores válidos. |
DirectoryNotFoundException | Parte de una ruta de acceso de directorio no es válida. |
DivideByZeroException | El denominador de una operación de entero o Decimal división es cero. |
DriveNotFoundException | Una unidad no está disponible o no existe. |
FileNotFoundException | No existe un archivo. |
FormatException | Un valor no está en un formato adecuado para convertirse de una cadena mediante un método de conversión como Parse . |
IndexOutOfRangeException | Un índice está fuera de los límites de una matriz o colección. |
InvalidOperationException | Una llamada al método no es válida en el estado actual de un objeto. |
KeyNotFoundException | No se encuentra la clave especificada para acceder a un miembro de una colección. |
NotImplementedException | No se implementa un método o una operación. |
NotSupportedException | No se admite un método o una operación. |
ObjectDisposedException | Se realiza una operación en un objeto que se ha eliminado. |
OverflowException | Una operación aritmética, de conversión o conversión produce un desbordamiento. |
PathTooLongException | Una ruta de acceso o nombre de archivo supera la longitud máxima definida por el sistema. |
PlatformNotSupportedException | La operación no se admite en la plataforma actual. |
RankException | Una matriz con el número incorrecto de dimensiones se pasa a un método . |
TimeoutException | El intervalo de tiempo asignado a una operación ha expirado. |
UriFormatException | Se usa un identificador uniforme de recursos (URI) no válido. |
Implementación de excepciones personalizadas
En los casos siguientes, el uso de una excepción de .NET Framework existente para controlar una condición de error no es suficiente:
Cuando la excepción refleja un error de programa único que no se puede asignar a una excepción de .NET Framework existente.
Cuando la excepción requiere controlar que es diferente del control adecuado para una excepción de .NET Framework existente, o la excepción debe eliminarse de una excepción similar. Por ejemplo, si inicia una ArgumentOutOfRangeException excepción al analizar la representación numérica de una cadena que está fuera del intervalo del tipo entero de destino, no querrá usar la misma excepción para un error que se produce cuando el autor de la llamada no proporciona los valores restringidos adecuados al llamar al método.
La Exception clase es la clase base de todas las excepciones de .NET Framework. Muchas clases derivadas se basan en el comportamiento heredado de los miembros de la Exception clase; no invalidan los miembros de Exception, ni definen ningún miembro único.
Para definir su propia clase de excepción:
Defina una clase que herede de Exception. Si es necesario, defina los miembros únicos que necesite la clase para proporcionar información adicional sobre la excepción. Por ejemplo, la ArgumentException clase incluye una ParamName propiedad que especifica el nombre del parámetro cuyo argumento provocó la excepción y la RegexMatchTimeoutException propiedad incluye una MatchTimeout propiedad que indica el intervalo de tiempo de espera.
Si es necesario, invalide los miembros heredados cuya funcionalidad desea cambiar o modificar. Tenga en cuenta que la mayoría de las clases derivadas existentes de Exception no invalidan el comportamiento de los miembros heredados.
Determine si el objeto de excepción personalizado es serializable. La serialización permite guardar información sobre la excepción y permite que un servidor y un proxy de cliente compartan información de excepciones en un contexto de comunicación remota. Para que el objeto de excepción sea serializable, ábalo con el SerializableAttribute atributo .
Defina los constructores de la clase de excepción. Normalmente, las clases de excepción tienen uno o varios de los constructores siguientes:
Exception(), que usa valores predeterminados para inicializar las propiedades de un nuevo objeto de excepción.
Exception(String), que inicializa un nuevo objeto de excepción con un mensaje de error especificado.
Exception(String, Exception), que inicializa un nuevo objeto de excepción con un mensaje de error especificado y una excepción interna.
Exception(SerializationInfo, StreamingContext), que es un
protected
constructor que inicializa un nuevo objeto de excepción a partir de datos serializados. Debe implementar este constructor si ha elegido serializar el objeto de excepción.
En el ejemplo siguiente se muestra el uso de una clase de excepción personalizada. Define una NotPrimeException
excepción que se produce cuando un cliente intenta recuperar una secuencia de números primos especificando un número inicial que no es primo. La excepción define una nueva propiedad, NonPrime
, que devuelve el número no primo que provocó la excepción. Además de implementar un constructor sin parámetros protegido y un constructor con SerializationInfo parámetros y StreamingContext para serialización, la NotPrimeException
clase define tres constructores adicionales para admitir la NonPrime
propiedad . Cada constructor llama a un constructor de clase base además de conservar el valor del número no primo. La NotPrimeException
clase también se marca con el SerializableAttribute atributo .
using System;
using System.Runtime.Serialization;
[Serializable()]
public class NotPrimeException : Exception
{
private int notAPrime;
protected NotPrimeException()
: base()
{ }
public NotPrimeException(int value) :
base(String.Format("{0} is not a prime number.", value))
{
notAPrime = value;
}
public NotPrimeException(int value, string message)
: base(message)
{
notAPrime = value;
}
public NotPrimeException(int value, string message, Exception innerException) :
base(message, innerException)
{
notAPrime = value;
}
protected NotPrimeException(SerializationInfo info,
StreamingContext context)
: base(info, context)
{ }
public int NonPrime
{ get { return notAPrime; } }
}
namespace global
open System
open System.Runtime.Serialization
[<Serializable>]
type NotPrimeException =
inherit Exception
val notAPrime: int
member this.NonPrime =
this.notAPrime
new (value) =
{ inherit Exception($"%i{value} is not a prime number."); notAPrime = value }
new (value, message) =
{ inherit Exception(message); notAPrime = value }
new (value, message, innerException: Exception) =
{ inherit Exception(message, innerException); notAPrime = value }
// F# does not support protected members
new () =
{ inherit Exception(); notAPrime = 0 }
new (info: SerializationInfo, context: StreamingContext) =
{ inherit Exception(info, context); notAPrime = 0 }
Imports System.Runtime.Serialization
<Serializable()> _
Public Class NotPrimeException : Inherits Exception
Private notAPrime As Integer
Protected Sub New()
MyBase.New()
End Sub
Public Sub New(value As Integer)
MyBase.New(String.Format("{0} is not a prime number.", value))
notAPrime = value
End Sub
Public Sub New(value As Integer, message As String)
MyBase.New(message)
notAPrime = value
End Sub
Public Sub New(value As Integer, message As String, innerException As Exception)
MyBase.New(message, innerException)
notAPrime = value
End Sub
Protected Sub New(info As SerializationInfo,
context As StreamingContext)
MyBase.New(info, context)
End Sub
Public ReadOnly Property NonPrime As Integer
Get
Return notAPrime
End Get
End Property
End Class
La PrimeNumberGenerator
clase que se muestra en el ejemplo siguiente usa el Sieve de Eratosthenes para calcular la secuencia de números primos de 2 a un límite especificado por el cliente en la llamada a su constructor de clase. El GetPrimesFrom
método devuelve todos los números primos que son mayores o iguales que un límite inferior especificado, pero produce un NotPrimeException
valor si ese límite inferior no es un número primo.
using System;
using System.Collections.Generic;
[Serializable]
public class PrimeNumberGenerator
{
private const int START = 2;
private int maxUpperBound = 10000000;
private int upperBound;
private bool[] primeTable;
private List<int> primes = new List<int>();
public PrimeNumberGenerator(int upperBound)
{
if (upperBound > maxUpperBound)
{
string message = String.Format(
"{0} exceeds the maximum upper bound of {1}.",
upperBound, maxUpperBound);
throw new ArgumentOutOfRangeException(message);
}
this.upperBound = upperBound;
// Create array and mark 0, 1 as not prime (True).
primeTable = new bool[upperBound + 1];
primeTable[0] = true;
primeTable[1] = true;
// Use Sieve of Eratosthenes to determine prime numbers.
for (int ctr = START; ctr <= (int)Math.Ceiling(Math.Sqrt(upperBound));
ctr++)
{
if (primeTable[ctr]) continue;
for (int multiplier = ctr; multiplier <= upperBound / ctr; multiplier++)
if (ctr * multiplier <= upperBound) primeTable[ctr * multiplier] = true;
}
// Populate array with prime number information.
int index = START;
while (index != -1)
{
index = Array.FindIndex(primeTable, index, (flag) => !flag);
if (index >= 1)
{
primes.Add(index);
index++;
}
}
}
public int[] GetAllPrimes()
{
return primes.ToArray();
}
public int[] GetPrimesFrom(int prime)
{
int start = primes.FindIndex((value) => value == prime);
if (start < 0)
throw new NotPrimeException(prime, String.Format("{0} is not a prime number.", prime));
else
return primes.FindAll((value) => value >= prime).ToArray();
}
}
namespace global
open System
[<Serializable>]
type PrimeNumberGenerator(upperBound) =
let start = 2
let maxUpperBound = 10000000
let primes = ResizeArray()
let primeTable =
upperBound + 1
|> Array.zeroCreate<bool>
do
if upperBound > maxUpperBound then
let message = $"{upperBound} exceeds the maximum upper bound of {maxUpperBound}."
raise (ArgumentOutOfRangeException message)
// Create array and mark 0, 1 as not prime (True).
primeTable[0] <- true
primeTable[1] <- true
// Use Sieve of Eratosthenes to determine prime numbers.
for i = start to float upperBound |> sqrt |> ceil |> int do
if not primeTable[i] then
for multiplier = i to upperBound / i do
if i * multiplier <= upperBound then
primeTable[i * multiplier] <- true
// Populate array with prime number information.
let mutable index = start
while index <> -1 do
index <- Array.FindIndex(primeTable, index, fun flag -> not flag)
if index >= 1 then
primes.Add index
index <- index + 1
member _.GetAllPrimes() =
primes.ToArray()
member _.GetPrimesFrom(prime) =
let start =
Seq.findIndex ((=) prime) primes
if start < 0 then
raise (NotPrimeException(prime, $"{prime} is not a prime number.") )
else
Seq.filter ((>=) prime) primes
|> Seq.toArray
Imports System.Collections.Generic
<Serializable()> Public Class PrimeNumberGenerator
Private Const START As Integer = 2
Private maxUpperBound As Integer = 10000000
Private upperBound As Integer
Private primeTable() As Boolean
Private primes As New List(Of Integer)
Public Sub New(upperBound As Integer)
If upperBound > maxUpperBound Then
Dim message As String = String.Format(
"{0} exceeds the maximum upper bound of {1}.",
upperBound, maxUpperBound)
Throw New ArgumentOutOfRangeException(message)
End If
Me.upperBound = upperBound
' Create array and mark 0, 1 as not prime (True).
ReDim primeTable(upperBound)
primeTable(0) = True
primeTable(1) = True
' Use Sieve of Eratosthenes to determine prime numbers.
For ctr As Integer = START To CInt(Math.Ceiling(Math.Sqrt(upperBound)))
If primeTable(ctr) Then Continue For
For multiplier As Integer = ctr To CInt(upperBound \ ctr)
If ctr * multiplier <= upperBound Then primeTable(ctr * multiplier) = True
Next
Next
' Populate array with prime number information.
Dim index As Integer = START
Do While index <> -1
index = Array.FindIndex(primeTable, index, Function(flag)
Return Not flag
End Function)
If index >= 1 Then
primes.Add(index)
index += 1
End If
Loop
End Sub
Public Function GetAllPrimes() As Integer()
Return primes.ToArray()
End Function
Public Function GetPrimesFrom(prime As Integer) As Integer()
Dim start As Integer = primes.FindIndex(Function(value)
Return value = prime
End Function)
If start < 0 Then
Throw New NotPrimeException(prime, String.Format("{0} is not a prime number.", prime))
Else
Return primes.FindAll(Function(value)
Return value >= prime
End Function).ToArray()
End If
End Function
End Class
En el ejemplo siguiente se realiza dos llamadas al GetPrimesFrom
método con números no primos, uno de los cuales cruza los límites del dominio de aplicación. En ambos casos, la excepción se produce y se controla correctamente en el código de cliente.
using System;
using System.Reflection;
class Example
{
public static void Main()
{
int limit = 10000000;
PrimeNumberGenerator primes = new PrimeNumberGenerator(limit);
int start = 1000001;
try
{
int[] values = primes.GetPrimesFrom(start);
Console.WriteLine("There are {0} prime numbers from {1} to {2}",
start, limit);
}
catch (NotPrimeException e)
{
Console.WriteLine("{0} is not prime", e.NonPrime);
Console.WriteLine(e);
Console.WriteLine("--------");
}
AppDomain domain = AppDomain.CreateDomain("Domain2");
PrimeNumberGenerator gen = (PrimeNumberGenerator)domain.CreateInstanceAndUnwrap(
typeof(Example).Assembly.FullName,
"PrimeNumberGenerator", true,
BindingFlags.Default, null,
new object[] { 1000000 }, null, null);
try
{
start = 100;
Console.WriteLine(gen.GetPrimesFrom(start));
}
catch (NotPrimeException e)
{
Console.WriteLine("{0} is not prime", e.NonPrime);
Console.WriteLine(e);
Console.WriteLine("--------");
}
}
}
open System
open System.Reflection
let limit = 10000000
let primes = PrimeNumberGenerator limit
let start = 1000001
try
let values = primes.GetPrimesFrom start
printfn $"There are {values.Length} prime numbers from {start} to {limit}"
with :? NotPrimeException as e ->
printfn $"{e.NonPrime} is not prime"
printfn $"{e}"
printfn "--------"
let domain = AppDomain.CreateDomain "Domain2"
let gen =
domain.CreateInstanceAndUnwrap(
typeof<PrimeNumberGenerator>.Assembly.FullName,
"PrimeNumberGenerator", true,
BindingFlags.Default, null,
[| box 1000000 |], null, null)
:?> PrimeNumberGenerator
try
let start = 100
printfn $"{gen.GetPrimesFrom start}"
with :? NotPrimeException as e ->
printfn $"{e.NonPrime} is not prime"
printfn $"{e}"
printfn "--------"
Imports System.Reflection
Module Example
Sub Main()
Dim limit As Integer = 10000000
Dim primes As New PrimeNumberGenerator(limit)
Dim start As Integer = 1000001
Try
Dim values() As Integer = primes.GetPrimesFrom(start)
Console.WriteLine("There are {0} prime numbers from {1} to {2}",
start, limit)
Catch e As NotPrimeException
Console.WriteLine("{0} is not prime", e.NonPrime)
Console.WriteLine(e)
Console.WriteLine("--------")
End Try
Dim domain As AppDomain = AppDomain.CreateDomain("Domain2")
Dim gen As PrimeNumberGenerator = domain.CreateInstanceAndUnwrap(
GetType(Example).Assembly.FullName,
"PrimeNumberGenerator", True,
BindingFlags.Default, Nothing,
{1000000}, Nothing, Nothing)
Try
start = 100
Console.WriteLine(gen.GetPrimesFrom(start))
Catch e As NotPrimeException
Console.WriteLine("{0} is not prime", e.NonPrime)
Console.WriteLine(e)
Console.WriteLine("--------")
End Try
End Sub
End Module
' The example displays the following output:
' 1000001 is not prime
' NotPrimeException: 1000001 is not a prime number.
' at PrimeNumberGenerator.GetPrimesFrom(Int32 prime)
' at Example.Main()
' --------
' 100 is not prime
' NotPrimeException: 100 is not a prime number.
' at PrimeNumberGenerator.GetPrimesFrom(Int32 prime)
' at Example.Main()
' --------
Windows Runtime y .NET Framework 4.5.1
En .NET para aplicaciones de la Tienda Windows 8.x para Windows 8, normalmente se pierde información de excepciones cuando se propaga una excepción a través de marcos de pila de non-.NET Framework. A partir de .NET Framework 4.5.1 y Windows 8.1, Common Language Runtime sigue usando el objeto original Exception que se produjo a menos que esa excepción se haya modificado en un marco de pila de non-.NET Framework.
Constructores
Exception() |
Inicializa una nueva instancia de la clase Exception. |
Exception(SerializationInfo, StreamingContext) |
Inicializa una nueva instancia de la clase Exception con datos serializados. |
Exception(String) |
Inicializa una nueva instancia de la clase Exception con el mensaje de error especificado. |
Exception(String, Exception) |
Inicializa una nueva instancia de la clase Exception con el mensaje de error especificado y una referencia a la excepción interna que representa la causa de esta excepción. |
Propiedades
Data |
Obtiene una colección de pares clave/valor que proporciona información definida por el usuario adicional sobre la excepción. |
HelpLink |
Obtiene o establece un vínculo al archivo de ayuda asociado a esta excepción. |
HResult |
Obtiene o establece HRESULT, un valor numérico codificado que se asigna a una excepción específica. |
InnerException |
Obtiene la instancia Exception que produjo la excepción actual. |
Message |
Obtiene un mensaje que describe la excepción actual. |
Source |
Devuelve o establece el nombre de la aplicación o del objeto que generó el error. |
StackTrace |
Obtiene una representación de cadena de los marcos inmediatos en la pila de llamadas. |
TargetSite |
Obtiene el método que produjo la excepción actual. |
Métodos
Equals(Object) |
Determina si el objeto especificado es igual que el objeto actual. (Heredado de Object) |
GetBaseException() |
Cuando se invalida en una clase derivada, devuelve la clase Exception que representa la causa principal de una o más excepciones posteriores. |
GetHashCode() |
Sirve como la función hash predeterminada. (Heredado de Object) |
GetObjectData(SerializationInfo, StreamingContext) |
Cuando se invalida en una clase derivada, establece SerializationInfo con información sobre la excepción. |
GetType() |
Obtiene el tipo de tiempo de ejecución de la instancia actual. |
GetType() |
Obtiene el Type de la instancia actual. (Heredado de Object) |
MemberwiseClone() |
Crea una copia superficial del Object actual. (Heredado de Object) |
ToString() |
Crea y devuelve una representación de cadena de la excepción actual. |
Eventos
SerializeObjectState |
Obsoleto.
Ocurre cuando una excepción se serializa para crear un objeto de estado de excepción que contenga datos serializados sobre la excepción. |