2009-09-23 15 views
34

¿Cómo puedo establecer la propiedad InnerException de un objeto Exception, mientras estoy en el constructor de ese objeto? Esto se reduce a encontrar y configurar el campo de respaldo de una propiedad que no tiene setter.Establecer InnerException del objeto .NET Exception

por cierto: He visto esto (http://evain.net/blog/articles/2009/05/01/getting-the-field-backing-a-property-using-reflection) pero estoy buscando una solución que no esté basada en IL, si es posible.

El constructor de excepción es el lugar donde se crea el tipo de excepción, por lo que no se puede llamar utilizando la MiExcepción constructor de la clase base(): base (...), etc.

+0

Re the follow up; luego (como mencioné) haga la creación de tipo en un método estático * adelante * del ctor, en lugar de dentro del cuerpo del constructor. –

+1

Tiene más sentido encapsular en mi caso. –

+0

... pero entiendo su punto, voy a ver cómo hacer de esto una fábrica para evitar el costo de la reflexión. –

Respuesta

12

¿Por qué no puedes simplemente llamar al constructor que toma la InnerException como parámetro? Si por alguna razón no es posible, el campo respaldo en System.Exception es:

private Exception _innerException; 

me pareció a cabo utilizando Redgate's Reflector. Usando el reflejo, supongo que podrías establecer la excepción interna.

Edit: En la mayoría de los casos, no es una buena idea acceder a los campos privados por reflexión, pero no sé lo suficiente sobre el caso de NT para saber si es una buena o mala idea.

+9

No puedo pensar en un ejemplo sensato donde la reflexión sea la manera correcta de hacerlo ... –

+0

Tiene sentido para escenarios dinámicos que involucran activaciones de excepciones donde la excepción interna no puede conocerse de antemano, por lo tanto no puede pasarse al constructor . –

+3

No, no es así. Realmente no lo hace; rompe la encapsulación. Use un método estático en la cadena ': base (SomeMethod (...), ...)'. –

7
Exception exceptionWithMoreInfo = new Exception("extra info", ex); 

sería una práctica normal asumiendo que atrapó una excepción a la que le gustaría agregar más información antes de burbujear.

+1

Esto no te ayuda en el código de la excepción, sin embargo. – Joey

59

configura la excepción interna llamando a la base de Héctor:

public MyException(string message, Exception innerException) 
     : base(message, innerException) {...} 

Si necesita ejecutar algún código para obtener la excepción, utilice un método estático:

public MyException(SomeData data) : base(GetMessage(data), GetInner(data)) {...} 
static Exception GetInner(SomeData data) {...} // <===== your type creation here! 
static string GetMessage(SomeData data) {...} 
1

No es InnerException se supone que se establece cuando se utiliza el constructor Exception(string, Exception) Creo que es por diseño que no se puede cambiar esto de otra manera, pero siempre se puede aplazar al constructor apropiado en el tiempo de construcción:

class MyException : Exception { 
    public MyException() 
     : base("foo", new Exception("bar")) 
    { 
     ... 
    } 

    ... 
} 

Creo que no debería nunca romper la cadena de excepción en su código, ya que por lo general conduce a errores que nunca encontrarás de nuevo.

29

La clase Exception tiene un constructor sobrecargado aceptar la excepción interna como parámetro:

Exception exc = new Exception("message", new Exception("inner message")); 

¿Es esto lo que busca?

+0

Si bien esto no responde su pregunta directamente, responde lo que la mayoría de las personas que buscaban esto buscaba. – rolls

1

Si entiendo su pregunta que queremos hacer algo como esto:

Exception ex = new Exception("test"); 
Exception innerEx = new Exception("inner"); 
ex.GetType().GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(ex, innerEx); 

Si se encuentra en el constructor de un objeto que hereda de Exception que usaría this en lugar de la primera ex.

Pero esta puede no ser la mejor manera de manejar lo que sea que esté tratando de manejar.

+0

¿Qué pasa con Exception innerEx = new Exception ("inner"); Excepción ex = nueva Excepción ("prueba", innerEx); ? –

+0

Está tratando de modificar el objeto ex que no se creó en el contexto, lo creo solo con el propósito de hacer una demostración. En realidad, en su caso, él está tratando de modificar esta instancia. – pauloya

+0

+1: Respondí a mi propia pregunta más bien tonta de cómo forzar a la excepción interna de una excepción a ser ella misma, lo que provoca cosas divertidas como que el método ToString() desencadene un desbordamiento de la pila. – Brian

1

Utilice el reflector de Redgate para encontrar el campo. Dudo que la implementación de Exception cambie alguna vez ... ¡Pero es un riesgo!

+0

¿Por qué dudaría de esto? ¿Qué base tienes para hacer esta evaluación? Si yo fuera Microsoft, cambiaría la implementación solo para molestar a los tontos que dependen de los detalles de implementación interna de las clases de otras personas. –

+2

Según la cantidad de detalles que han cambiado en las últimas actualizaciones de marco? –

+1

@John: ¡Bueno, entonces no estás trabajando para MS! – Scooterville

0

Sé que llego muy tarde a la fiesta, pero me parece que esto funciona.

public class MyException: Exception 
{ 
    public void SetInnerException(Exception exception) 
    { 
     typeof(Exception) 
      .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance) 
      .SetValue(this, exception); 
    } 
} 

El truco es conseguir el campo _innerException real Exception de tipo y, a continuación, establezca el valor de excepción interna a la instancia de la clase (MyException en este caso).

Esto también funciona para las variables.

Exception mainException = new Exception(); 
typeof(Exception) 
    .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance) 
    .SetValue(mainException , new Exception("Something bad happened!"));