Définir InnerException of.NET objet D'Exception

Comment puis-je définir la propriété InnerException d'un objet Exception, alors que je suis dans le constructeur de cet objet? Cela se résume à trouver et à définir le champ de sauvegarde d'une propriété qui n'a pas de setter.

Btw: j'ai vu ceci (http://evain.net/blog/articles/2009/05/01/getting-the-field-backing-a-property-using-reflection) mais à la recherche d'une solution non basée sur IL, si possible.

Le constructeur D'Exception est l'endroit où le type D'Exception est créé, donc je ne peux pas l'appeler utilisation du constructeur de classe de base MyException (): base(...) etc.

37
demandé sur MikeTheLiar 2009-09-23 19:35:58

8 réponses

Pourquoi ne pouvez-vous pas simplement appeler le constructeur en prenant L'InnerException comme paramètre? Si pour une raison quelconque ce n'est pas possible, le champ de sauvegarde dans le système.L'Exception est:

private Exception _innerException;

Je l'ai découvert en utilisant le réflecteur de Redgate . En utilisant la réflexion, je suppose que vous pouvez définir l'exception interne.

Edit: dans la plupart des cas, ce n'est pas une bonne idée d'accéder aux champs privés via la réflexion, mais je n'en sais pas assez sur le cas de NT pour savoir avec certitude si c'est une bonne ou une mauvaise idée.

12
répondu Meta-Knight 2009-09-23 20:53:05

Vous définissez l'exception interne en appelant le ctor de base:

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

Si vous avez besoin d'exécuter du code pour obtenir l'exception, utilisez une méthode statique:

public MyException(SomeData data) : base(GetMessage(data), GetInner(data)) {...}
static Exception GetInner(SomeData data) {...} // <===== your type creation here!
static string GetMessage(SomeData data) {...}
68
répondu Marc Gravell 2009-09-23 16:00:37

La classe Exception a un constructeur surchargé acceptant l'exception interne en tant que paramètre:

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

Est-ce ce que vous recherchez?

31
répondu Paolo Tedesco 2009-09-23 15:41:42
Exception exceptionWithMoreInfo = new Exception("extra info", ex);

Serait une pratique normale en supposant que vous avez piégé une exception à laquelle vous souhaitez ajouter plus d'informations avant de bouillonner.

7
répondu dove 2009-09-23 15:38:53

InnerException n'est-il pas censé être défini lors de l'utilisation du constructeur Exception(string, Exception)? Je pense que c'est par conception que vous ne pouvez pas changer cela sinon, mais vous pouvez toujours vous en remettre au constructeur approprié au moment de la construction:

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

    ...
}

Je pense que vous ne devriez jamais casser la chaîne d'exception dans votre code car cela conduit généralement à des erreurs que vous ne retrouverez jamais.

1
répondu Joey 2009-09-23 15:41:16

Si je comprends votre question, vous voulez faire quelque chose comme ceci:

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

Si vous êtes dans le constructeur d'un objet qui hérite D'Exception, vous utiliseriez this au lieu du premier ex.

Mais ce n'est peut-être pas la meilleure façon de gérer ce que vous essayez de gérer.

1
répondu pauloya 2009-09-23 15:57:21

Utilisez le réflecteur de Redgate pour trouver le champ. Je doute que la mise en œuvre de L'exception changera jamais... Mais c'est un risque!

1
répondu NT_ 2009-10-05 15:05:49

Je sais que je suis vraiment en retard à la fête, mais je trouve que cela fonctionne.

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

L'astuce consiste à obtenir le champ _innerException du type Exception réel, puis à définir la valeur de l'exception interne sur votre instance de classe (MyException dans ce cas).

Cela fonctionne également pour les variables.

Exception mainException = new Exception();
typeof(Exception)
    .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
    .SetValue(mainException , new Exception("Something bad happened!"));
0
répondu 2015-07-14 08:42:48