我正在尝试更容易地检查null异常,所以我创建了这个静态方法:
/// <summary>
/// Static method for throwing multiple argument null exceptions
/// </summary>
/// <param name="arguments">An array of arguments</param>
public static void ArgumentIsNull(params object[] arguments)
{
// For each argument, if the argument is null, throw an error
foreach (var argument in arguments)
if (argument == null)
throw new ArgumentNullException(String.Format(Resources.ArgumentNullException, nameof(argument)));
}
问题是,我的错误看起来像这样:
您缺少必需的参数:参数
我知道这是因为我循环的参数名称
var argument in arguments
我想要做的是获取传递的参数的名称。 例如,这是对此方法的调用:
/// <summary>
/// Default constructor
/// </summary>
/// <param name="unitOfWork"></param>
/// <param name="service"></param>
/// <param name="apiKey"></param>
public SendGridProvider(IUnitOfWork unitOfWork, EmailService service, string apiKey)
: base(apiKey, "https://api.sendgrid.com/v3/")
{
// Throw an error if our key is not provided
ThrowIf.ArgumentIsNull(unitOfWork, service, apiKey);
// Assign our fields
this.apiKey = apiKey;
this.service = service;
this.unitOfWork = unitOfWork;
}
所以如果 unitOfWork 为空,我希望错误是
您缺少必需的参数:unitOfWork
我怎样才能做到这一点?
答案 0 :(得分:4)
不幸的是,没有可靠的方法(除非你使用一些自定义的后编译代码编织工具)。 nameof(
在编译时解析,传入的变量在运行时设置。
在优化构建中,局部变量甚至在编译的IL代码中的任何位置都没有原始变量名称。
以下是通过代码编织执行基本NameOf功能的Fody extension的示例,也许您可以扩展它的作用,让它看看传入的内容并传递string[]
到抓住参数名称。
答案 1 :(得分:2)
public static void ThrowIfNull<T>(params Expression<Func<T>>[] exprs)
{
foreach(var expr in exprs)
{
var member = expr.Body as MemberExpression;
var name = member.Member.Name;
var value = expr.Compile()();
if (value == null)
{
throw new ArgumentNullException(name);
}
}
}
由于名称只是获取变量的名称,这不可能直接实现,但您始终可以滥用表达式!
调用它看起来像:
public void DoSomething(string x, string y)
{
Ext.ThrowIfNull(() => x, () => y);
}
请记住,使用类型化方法会限制调用它来使用共享相同泛型类型(或公共子类型/接口)的表达式。
只需删除泛型类型并使用object
即可支持不同类型的表达式:
void ThrowIfNull(params Expression<Func<object>>[] exprs)
答案 2 :(得分:1)
如果你不想进入代码编织,并且想要一个实用工具方法来允许轻松的异常抛出,同时仍然提供足够的细节以解决你的错误,你可以将参数传递为Dictionary<string, object>
(或者我认为是Tuple
)而不是使用params关键字并传递数组。
ThrowIf.ArgumentIsNull(new Dictionary<string, object>()
{
{nameof(unitofwork), unitOfWork},
{nameof(service), service}
});
诚然,这并不像仅仅通过一系列参数一样性感。但它会满足您的要求。