web-dev-qa-db-fra.com

Comment définir InnerException de l'objet Exception .NET

Comment définir la propriété InnerException d'un objet Exception pendant que je suis dans le constructeur de cet objet? Cela revient à rechercher et à définir le champ de sauvegarde d'une propriété qui n'a pas de paramètre.

BTW: J'ai vu ceci evain.net - Obtenir le champ sauvegardant une propriété à l'aide de Reflection mais en recherchant une solution non basée sur IL, si possible.

Le constructeur de Exception est l'endroit où le type Exception est créé. Je ne peux donc pas l'appeler à l'aide du constructeur de la classe de base MyException() :base(...) etc.

39
_NT

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

private Exception _innerException;

Je l'ai trouvé en utilisant Reflector 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 ne connais pas suffisamment le cas de NT pour savoir avec certitude si c'est une bonne ou une mauvaise idée.

12
Meta-Knight

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

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

Si vous devez 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) {...}
73
Marc Gravell

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?

35
Paolo Tedesco
Exception exceptionWithMoreInfo = new Exception("extra info", ex);

ce serait une pratique normale de supposer que vous ayez piégé une exception à laquelle vous voudriez ajouter plus d’informations avant de commencer à bouillonner.

7
dove

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

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.

2
pauloya

Utilisez le réflecteur de Redgate pour trouver le champ. Je doute que l'implémentation d'Exception change jamais ... Mais c'est un risque!

1
NT_

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, 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 briser la chaîne des exceptions dans votre code car cela entraîne généralement des erreurs que vous ne retrouverez plus jamais.

1
Joey

Dans ma situation, j'ai utilisé ce code:

class Foo 
{
    void Bar(MyException myException = null)
    {
        try
        {
            SomeActions.Invoke();
        }
        catch (Exception ex)
        {
            if (myException != null)
            {
                // Here I regenerate my exception with a new InnerException
                var regenMyException = (MyException)System.Activator.CreateInstance(myException.GetType(), myException.Message, ex);
                throw regenMyException;
            }

            throw new FooBarException("Exception on Foo.Bar()", ex);
        }
    }
}

HTH quelqu'un;).

0
shA.t

Je sais que je suis vraiment en retard à la fête, mais je trouve que ça marche.

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 actuel, puis à définir la valeur d'exception interne sur votre instance de classe (MyException dans ce cas).

Cela fonctionne aussi pour les variables.

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