What exception to throw from a property setter?

C#ValidationExceptionProperties

C# Problem Overview


I have a string property that has a maximum length requirement because the data is linked to a database. What exception should I throw if the caller tries to set a string exceeding this length?

For example, this C# code:

public string MyProperty
{
    get
    {
        return _MyBackingField;
    }
    set
    {
        if (value.Length > 100)
            throw new FooException("MyProperty has a maximum length of 100.");

        _MyBackingField = value;
    }
}

I considered ArgumentException, but it just doesn't seem right. Technically, it is a function - MyProperty_set(string value) - so a case for ArgumentException can be made, but it's not being called as a function to the consumer's eyes - it's on the right side of an assignment operator.

This question could probably also be extended to include all kinds of data validation done in property setters, but I'm particularly interested in the above case.

C# Solutions


Solution 1 - C#

Have a look through mscorlib.dll with Reflector, in a similar situation such as System.String.StringBuilder.Capacity Microsoft use ArgumentOutOfRangeException() similar to:

public int PropertyA
{
    get
    {
        return //etc...
    }
    set
    {
        if (condition == true)
        {
            throw new ArgumentOutOfRangeException("value", "/* etc... */");
        }
        // ... etc
    }
}

Solution 2 - C#

To me ArgumentException (or a child) makes more sense, because the argument (value) you provided is not valid, and this is what ArgumentException was created for.

Solution 3 - C#

I wouldn't throw an exception at all. Rather I would allow a string of any length and then have a seperate "Validate" method on the class that is called before saving. There are a number of scenarios particularly if you use databinding where throwing exceptions from property setters can get you in a mess.

The trouble with throwing exceptions from property setters is that programmers forget to catch them. It kind of depends upon how clean you expect the data you are getting to be. In this case I would expect long string lengths to be common not exceptional and as such using an exception would be "flow control with exceptions".

To quote from the Microsoft's Design Guidelines for Developing Class Libraries:

> Do not use exceptions for normal flow > of control, if possible. Except for > system failures and operations with > potential race conditions, framework > designers should design APIs so that > users can write code that does not > throw exceptions. For example, you can > provide a way to check preconditions > before calling a member so that users > can write code that does not throw > exceptions.

Solution 4 - C#

Remember how many problems in computer science are solved by adding an extra level of indirection?

One approach would be to create a new type, FixedLengthString, say. It would be instances of that type that validate lengths of strings they are initialised with - with a conversion operator to do type conversion from a plain string. If your property setter takes such a type as its argument then any violation would become a type conversion exception instead of an argument/ property exception.

In practice I would rarely do this. It smells a bit of taking OO too far - but in some cases it can be a useful technique, so I mention it here for completeness.

Solution 5 - C#

public IPAddress Address
{
    get
    {
        return address;
    }
    set
    {
        if(value == null)
        {
            throw new ArgumentNullException("value");
        }
        address = value;
    }
}

via MSDN

Solution 6 - C#

You may use InvalidOperationException. That's a compromise. I wouldn't bother using an ArgumentException either.

Solution 7 - C#

Try to use existing exceptions whereever possible. In this case use InvalidOperationException because the incoming value is bringing the object in an inconsistent state. Custom exceptions can be created when a specific handling with the custom exception is needed. In this case you only throw an exception with some text, so use the InvalidOperationException.

When throwing the InvalidOperationException show the value that has been passed to this setter.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionlc.View Question on Stackoverflow
Solution 1 - C#Richard SlaterView Answer on Stackoverflow
Solution 2 - C#Davide VostiView Answer on Stackoverflow
Solution 3 - C#Martin BrownView Answer on Stackoverflow
Solution 4 - C#philsquaredView Answer on Stackoverflow
Solution 5 - C#javrosView Answer on Stackoverflow
Solution 6 - C#SaschaView Answer on Stackoverflow
Solution 7 - C#Patrick PetersView Answer on Stackoverflow