40 votes

C# - Pourquoi mettre en œuvre des constructeurs d'exception standard ?

De MSDN, avertissement d'analyse de code CA1032 :

Exception types must implement the following constructors: 

*   public NewException() 

*   public NewException(string) 

*   public NewException(string, Exception) 

*   protected or private NewException(SerializationInfo, StreamingContext)

Je comprends l'objectif derrière le constructeur de sérialisation, mais quelle est la raison pour laquelle il faut "exiger" les autres ? Pourquoi ne devrais-je pas définir les constructeurs qui ont un sens pour l'utilisation de mon exception ? Et si je ne veux jamais lancer MonException sans passer par un message, pourquoi devrais-je définir un constructeur sans paramètre ? Et si je veux que MonException ait une propriété int et que je ne veux que des constructeurs qui initialisent cette propriété ?

16voto

Matthew Flaschen Points 131723

Il s'agit d'un avertissement et non d'une obligation. Il s'agit essentiellement le principe de la moindre surprise . Le fait de fournir ces quatre éléments permet aux personnes habituées aux exceptions "normales" de C# d'utiliser plus facilement les vôtres. Si vous avez une bonne raison d'ignorer cette directive, faites-le. Mais cela brisera certains scénarios d'utilisation et rendra votre classe un peu moins intuitive.

11voto

Fredrik Mörk Points 85694

Vous avez obtenu de bonnes réponses. Je veux juste ajouter que fournir ces constructeurs supplémentaires ne nécessite pas nécessairement beaucoup de codage. Comme ils sont déjà implémentés dans la classe de base, vous pouvez simplement laisser celle-ci faire le travail :

public class MyCustomException : Exception
{
    public MyCustomException() : base() { }
    public MyCustomException(string message) : base(message) { }
    public MyCustomException(string message, Exception innerException) : base(message, innerException) { }
    // and so on...
}

Vous ne devrez donc implémenter du code que lorsque le comportement de votre exception s'écarte de celui de la classe de base.

8voto

Daniel Earwicker Points 63298

Les constructeurs parameterless et Serialization sont utilisés par le code générique de "routage des exceptions" qui doit déplacer les exceptions entre les domaines (par exemple, sur Internet entre un service et un client).

Celui qui en prend un autre Exception c'est pour qu'il soit possible de chaîner toutes les exceptions via la fonction InnerException propriété.

Enfin, il y a celle qui prend une chaîne de messages, ce qui aide à rendre l'utilisation des exceptions raisonnablement cohérente.

5voto

jrista Points 20950

L'implémentation des constructeurs d'exception standard permet aux gens d'utiliser votre exception d'une manière standard et familière qui est intégrée à toutes les exceptions .NET existantes. Les trois premiers peuvent être optionnels, si pour une raison quelconque vous ne voulez pas que l'un d'entre eux soit utilisé (bien que je ne puisse pas comprendre pourquoi vous voudriez cela.) Cependant, le dernier est le constructeur de désérialisation, et si vous souhaitez que votre exception soit supportée dans n'importe quel type d'environnement distribué (.NET Remoting, ASP.NET Web Services, WCF, etc.), alors il est pratiquement essentiel.

Sans un constructeur de désérialisation et l'attribut [Serializable], vos exceptions ne fonctionneront pas dans un environnement distribué et pourraient éventuellement causer d'autres problèmes. Compte tenu de ce qui précède et de l'aspect familier pour les développeurs C# expérimentés, il est préférable d'implémenter au moins les 4 constructeurs d'exception standard et de marquer vos exceptions avec [Serializable].

0voto

Timothy Points 41

Pourquoi ? Parce que. (Parce que d'après les autres réponses, le constructeur sans paramètre est nécessaire pour le routage des exceptions).

Je suis dans la même situation, et je ne veux pas construire accidentellement une exception sans mon paramètre de code d'erreur. Voici donc ce que j'ai fait :

public class MyException : ArgumentException
{
    [Obsolete("Use a constructor that takes an ErrorCode instead")]
    public MyException() { }

    [Obsolete("Use a constructor that takes an ErrorCode instead")]
    public MyException(string message) : base(message) { }

    [Obsolete("Use a constructor that takes an ErrorCode instead")]
    public MyException(string message, Exception innerException) : base(message, innerException) { }

    public MyException(ErrorCode errorCode, string message) : base(message) { /* use error code */ }

    public MyException(ErrorCode errorCode, string message, Exception innerException) : base(message, innerException) { /* use error code */ }

    protected MyException(SerializationInfo info, StreamingContext context) : base(info, context)
    {
        if (info != null)
        {
            // error code stuff
        }
    }

    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        if (info != null)
        {
            // error code stuff
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X