前言
在前面的文章中(《可空引用类型》),我们介绍过编译器会帮我们检查空引用,但是仅仅是警告。最好的方式还是在运行时用卫语句进行检查:
private void Test(WeatherForecast weatherForecast)
{if (weatherForecast == null){ throw new ArgumentNullException(nameof(weatherForecast));}
}
在.NET 6中,在ArgumentNullException类中添加了一个名为ThrowIfNull
的新静态方法,它允许我们快速检查和抛出 ArgumentNullExceptions:
有意思的是,异常信息自动带出了参数名称,这样可以有效避免使用nameof
用错参数。
那这是怎么做到的呢?
原理探究
查看ThrowIfNull
的定义,可以看到还有一个默认参数,使用了CallerArgumentExpression
属性声明:
public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression("argument")] string? paramName = null)
在编译时,编译器会把上面的代码编译成如下形式,传入了参数名:
ArgumentNullException.ThrowIfNull(weatherForecast, "weatherForecast");
原理利用
很可惜,.NET 6没有提供更多类似ThrowIfNull
的帮助方法,但是我们可以利用CallerArgumentExpression
实现自己的帮助类来简化卫语句。
比如:
public class ArgumentExceptionHelper {public static void ThrowIfNullOrEmpty(string? argument, [CallerArgumentExpression("argument")] string? paramName = null){if(string.IsNullOrEmpty( argument))throw new ArgumentNullException(paramName);}public static void ThrowIfOutOfRange(bool argument, [CallerArgumentExpression("argument")] string? paramName = null){if (argument)throw new ArgumentOutOfRangeException(paramName);}
}//使用
ArgumentExceptionHelper.ThrowIfNullOrEmpty(name);ArgumentExceptionHelper.ThrowIfOutOfRange(age <= 0);
最为奇妙的是,CallerArgumentExpression的功能是表示一个参数将传递给另一个参数的表达式作为字符串捕获。
,错误提示的不是参数名称,而是实际传入的表达式,因此更清晰。
例如下面的错误提示Age<=0:
结论
在.NET 6之前,.NET中已有三个[Caller*]属性可用:
[CallerMemberName]
[CallerFilePath]
[CallerLineNumber]
详细介绍请参看:https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callermembernameattribute
利用这些属性,可以让编译器“神奇地”填充它们,帮助我们轻松获取调用者信息。
如果你觉得这篇文章对你有所启发,请帮忙点个赞或者在看