静态抛出类:好或坏的做法
本文关键字:静态 | 更新日期: 2023-09-27 18:13:40
抛出异常通常遵循以下模式:
if(condition) { throw exception; }
检查条件,如果满足条件,则抛出异常。所以,我想知道它是不是一个好主意,为它写一个静态类,可能看起来像这样:
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);
}
}
(注意:这里没有定义ArgumentNullOrEmptyException
,但它的功能与您期望的差不多)
与其重复写这样的东西
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
}
我确实喜欢它,但这也是一个好的实践吗?
这样可以避免一些代码重复(if…扔),所以从这个意义上说,这是个好主意。只是要注意,从事代码工作的人需要知道Throw
API才能阅读和理解代码。
一个改进可以是使用表达式树来摆脱字符串参数名称传递。这将进一步提高简单性,并且您不必担心在重构等过程中键入字符串并保持它们正确。
例如,在我目前的宠物项目中,我有这个守卫类(缩短了一点):
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;
}
}
我可以这样使用
Guard.NotNull(() => someParameter);
这个模式没有任何问题,我已经在许多应用程序中看到过它。这主要是个人风格的问题。
然而,有一件事要注意这种模式:它改变了资源字符串的性能语义。对于有本地化错误消息的应用程序/库,模式为
if (...) {
throw new ArgumentExecption("paramName", LoadSomeResource(ErrorId));
}
虽然加载资源并不便宜,但也不是免费的。在上面的模式中,当发生错误时,资源是按需加载的。在您的模式中,它将被急切地加载。这意味着即使没有任何违反方法契约的情况,应用程序中的每个资源字符串也会被急切地加载。很可能不是你想要做的。
我会考虑使用代码契约。