Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static Throw class: good or bad practice

Throwing exceptions often follows the following pattern:

if(condition) { throw exception; }

you check a condition, and if the condition is satisfied, you throw an exception. So, i was wondering if it is good idea to write a static class for it that could look like this:

public static class Throw
{
    public static void IfNullOrEmpty<T>(string @string, params object[] parameters) where T : Exception
    {
        Throw.If<T>(string.IsNullOrEmpty(@string), parameters);
    }

    public static void IfNullOrEmpty<T, I>(IEnumerable<I> enumerable, params object[] parameters) where T : Exception
    {
        Throw.If<T>(enumerable == null || enumerable.Count() == 0, parameters);
    }

    public static void IfNullOrEmpty(string @string, string argumentName)
    {
        Throw.IfNullOrEmpty(@string, argumentName, 
            string.Format("Argument '{0}' cannot be null or empty.", argumentName));
    }

    public static void IfNullOrEmpty(string @string, string argumentName, string message)
    {
        Throw.IfNullOrEmpty<ArgumentNullOrEmptyException>(@string, message, argumentName);
    }

    public static void IfNullOrEmpty<I>(IEnumerable<I> enumerable, string argumentName)
    {
        Throw.IfNullOrEmpty(enumerable, argumentName, 
            string.Format("Argument '{0}' cannot be null or empty.", argumentName));
    }

    public static void IfNullOrEmpty<I>(IEnumerable<I> enumerable, string argumentName, string message)
    {
        Throw.IfNullOrEmpty<ArgumentNullOrEmptyException, I>(enumerable, message, argumentName);
    }


    public static void IfNull<T>(object @object, params object[] parameters) where T : Exception
    {
        Throw.If<T>(@object == null, parameters);
    }

    public static void If<T>(bool condition, params object[] parameters) where T : Exception
    {
        if (condition) 
        {
            var types = new List<Type>();
            var args = new List<object>();
            foreach (object p in parameters ?? Enumerable.Empty<object>())
            {
                types.Add(p.GetType());
                args.Add(p);
            }

            var constructor = typeof(T).GetConstructor(types.ToArray());
            var exception = constructor.Invoke(args.ToArray()) as T;
            throw exception;
        }
    }

    public static void IfNull(object @object, string argumentName)
    {
        Throw.IfNull<ArgumentNullException>(@object, argumentName);
    }
}

(Note: The ArgumentNullOrEmptyExceptionis not defined here, but it does pretty much what one would expect.)

so instead of repeatedly writing stuff like that

void SomeFunction(string someParameter)
{
   if(string.IsNullOrEmpty(someParameter))
   {
      throw new ArgumentNullOrEmptyException("someParameter", "Argument 'someParameter' cannot be null or empty.");
   }
}

i just do

void SomeFunction(string someParameter)
{
   Throw.IfNullOrEmpty(someParameter, "someParameter"); // not .IsNullOrEmpty
}

i actually do like it, but is it also a good practice?

like image 919
esskar Avatar asked Nov 07 '11 21:11

esskar


2 Answers

You get rid of a bit of code duplication this way (the if ... throw), so in that sense it is a good idea. Just be aware that people working on the code would need to know the Throw API to be able to read and understand the code.

One improvement could be to use expression trees to get rid of the string parameter name passing. This would improve the simplicity further, and you wouldn't have to worry about typing the strings and keeping them correct during refactorings and such.

For instance, on my current pet project I have this Guard class (shortened a bit):

public static class Guard
{
    public static void NotNullOrEmpty(Expression<Func<string>> parameterExpression)
    {
        string value = parameterExpression.Compile()();
        if (String.IsNullOrWhiteSpace(value))
        {
            string name = GetParameterName(parameterExpression);
            throw new ArgumentException("Cannot be null or empty", name);
        }
    }

    public static void NotNull<T>(Expression<Func<T>> parameterExpression)
        where T : class
    {
        if (null == parameterExpression.Compile()())
        {
            string name = GetParameterName(parameterExpression);
            throw new ArgumentNullException(name);
        }
    }

    private static string GetParameterName<T>(Expression<Func<T>> parameterExpression)
    {
        dynamic body = parameterExpression.Body;
        return body.Member.Name;
    }
}

Which I can then use like this:

Guard.NotNull(() => someParameter);
like image 183
driis Avatar answered Oct 01 '22 12:10

driis


There is nothing wrong with this pattern and I've seen it done in a number of applications. It's mostly a matter of personal style.

However there is one thing to be aware of with this pattern though: it changes the perf semantics for resource strings. It apps / libraries which have localized error messages the pattern is

if (...) {
  throw new ArgumentExecption("paramName", LoadSomeResource(ErrorId));
}

While loading a resource is not cheap it's not free either. In the pattern above the resource is loaded on demand when an error occurs. In your pattern it would be loaded eagerly instead. This means that every resource string in the application would be loaded eagerly even if there were never any violation of method contracts. Very likely not what you were expecting to do.

like image 38
JaredPar Avatar answered Oct 01 '22 11:10

JaredPar