views:

82

answers:

4

In the example code below I am taking a list of strings and concatenating them to a delimited string. The problem occurs when I use the setter with an empty list. The ToString method throws an ArgumentOutOfRangeException since the second parameter is a -1.

How should conditions (exceptions thrown in getters/setters) like this be handled?

I don't like the fact that the setter throws an exception since the caller doesn't know about the internals of the class and therefor should not have to handle (or even know how) the exception. Catching all exceptions in the getter/setter and quietly handling them also sounds like a bad idea since the caller will not know the getter/setter failed.

//I realize that this isn't the best code but I wanted to produce an example
//to demonstrate my question.
private string theStringVariable;
const string DELIMITER = ",";

public IList<string> StringList
{
   set
   {
      StringBuilder stringBuilder = new StringBuilder();
      foreach(string entry in value)
      {
         stringBuilder.Append(entry);
         stringBuilder.Append(DELIMITER);
      }
      theStringVariable = stringBuilder.ToString(0, stringBuilder.Length - 1);
   }
}
+6  A: 

You should check for the potential, common error conditions, and throw your own exception (prior to the StringBuilder errors) right up front, with a meaningful error message.

In your case, you'll most likely want to use some form of ArgumentException if the setter is called with an Empty string list. The key here is that your exception can say "the argument contained an empty collection" instead of "index out of bounds", which is going to make the caller understand, immediately, why they have a "real" problem in their call.


On a side note: In cases like the code you posted - I'd also consider making this a method instead of a property. You're doing quite a bit of "work" in this property setter, which is going to be somewhat unexpected. By making this a method, you'll be giving the user a clue that there's a bit of "processing" occurring within this property...

Reed Copsey
+1 I agree, if you need to do enough work to be concerned with catching an exception then it probably deserves a method.
Lucas B
Better reason to make it a method: It seems to be a "write-only" property. That rarely a good idea.
James Curran
@James: Yeah - although the "real" property may have a getter, I think, since the OP was concerned about this for get and set. Not sure if this is the full code, or just a sample...
Reed Copsey
@Reed - From the way it's used (He doesn't store the list, just the assembled string), I don't expect there's a getter at all.
James Curran
@James: It's possible - it's also possible that a getter could just as easily do a String.Split operation and return a list... In any case, I'd still make this a method ;)
Reed Copsey
@James: In the real code there is a getter and a setter. I left the getter out in effort to reduce noise and give a concise example.
brainimus
+1  A: 

I don't think your issues deal with best practices.

The best practice you need to watch in your case is the line that says

 stringBuilder.ToString(0, stringBuilder.Length - 1);

You are causing the exception to be thrown by not checking the string length. If your length is 0, just return empty string.

If we are talking in generalities, if you have the ability to code around common issues, empty sets, badly formatted data, then you should do your best to shield the user from unnecessary errors.

However* sometimes it is better to abruptly/loudly fail then it is to silently fail.

Nix
A: 

First of all, if you can spot someone that might cause an exception --- fix it so the exception doesn't happen. In this case, check for an empty list before the loop and set the varaible appropriately.

Otherwise, catch the exceptions (the one you expect might happen(*)), an throw a new more appropriate exception (with the original as the inner exception)

(*) Catch only the one's you expect might happen -- let the unexpected one bubble up to the user.

James Curran
A: 

Code Complete suggests if you can handle the exception locally that you do so: "Don't use an exception to pass the buck". In the example given this would mean check for an empty value and handle this appropriately in the setter.

rtalbot