Alexis
Alexis

Reputation: 541

Why implement the standard exception constructors in C#?

From MSDN, code analysis warning CA1032:

Exception types must implement the following constructors:

  • public NewException()
  • public NewException(string)
  • public NewException(string, Exception)
  • protected or private NewException(SerializationInfo, StreamingContext)

I understand the purpose behind the serialization constructor, but what is the rationale behind "requiring" the others?

Why shouldn't I just define whatever constructors make sense for usage of my custom exception? What if I never want to throw MyException without passing in a message– why should I define a parameterless constructor? What if I want MyException to have an int property and I only want constructors that initialize that property?

Upvotes: 49

Views: 10120

Answers (7)

SerG
SerG

Reputation: 1340

It's just another Cargo cult. Someone once decided it's a good idea to make so (obviously most probably having strong relevant justifying experience) but with years of language evolution real reasoning has been replaced by repeating the dogma: just do as we used to do, don't ask.

Do we really want to allow custom exception being created with uninitialized custom property (if one presented)?

Do we really want to support serialization of our custom exception?

One aspect we most probably want is possibility to instantiate custom exception from client code to make it possible to test how our exception is handled.

Upvotes: 4

Timothy
Timothy

Reputation: 41

Why? Because. (Because from other answers, the parameterless constructor is required for exception routing.)

I'm in the same place, and I don't want to accidentally construct an exception without my error code parameter. So here's what I did:

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
        }
    }
}

Upvotes: 0

Matthew Flaschen
Matthew Flaschen

Reputation: 284796

This is a warning, not a requirement. It's basically principle of least surprise. Providing all 4 makes it easier for people used to "regular" C# exceptions to use yours. If you have a good reason to ignore the guideline, do so. But it will break certain usage scenarios, and make your class a little less intuitive.

Upvotes: 19

jrista
jrista

Reputation: 32960

Implementing the standard exception constructors allow people to use your exception in a standard, familiar way that is built into all existing .NET exceptions. The first three can be optional, if for some reason you don't want one of them to be used (although why you would want that I couldn't fathom.) However, the last one is the deserialization constructor, and if you wish your exception to be supported in any kind of distributed environment (.NET Remoting, ASP.NET Web Services, WCF, etc.), then its is pretty much essential.

Without a deserialization constructor and the [Serializable] attribute, your exceptions won't function in a distributed environment, and could possibly cause other problems. Given that, and the aspect of familiarity to well-versed C# developers, its best to implement at least the 4 standard exception constructors, and mark your exceptions with [Serializable].

Upvotes: 5

Fredrik Mörk
Fredrik Mörk

Reputation: 158309

You have gotten some good answers. I just want to add that providing these extra constructors does not necessarily require a lot of coding. Since they are already implemented in the base class, you can simply let that one do the work:

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...
}

So you will only need to implement code where the behaviour of your exception deviates from that of the base class.

Upvotes: 12

Daniel Earwicker
Daniel Earwicker

Reputation: 116674

The parameterless and Serialization constructors are used by generic "exception routing" code that needs to move exceptions around between domains (e.g. across the internet between a service and a client).

The one that takes another Exception is so that it is possible to chain all exceptions via the InnerException property.

Finally, there's the one that takes a message string, which helps to make use of exceptions reasonably consistent.

Upvotes: 9

mqp
mqp

Reputation: 71935

Well, the constructor that takes an inner exception is pretty much necessary to make a custom exception properly usable. Without it, if someone caught your exception, they couldn't fire off a more descriptive or appropriate exception while preserving your original one (and the information it carries, like the stack trace.)

Upvotes: -2

Related Questions