c#nameof原始参数被覆盖

时间:2016-05-20 13:47:46

标签: c#

我正在尝试更容易地检查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

我怎样才能做到这一点?

3 个答案:

答案 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}
});

诚然,这并不像仅仅通过一系列参数一样性感。但它会满足您的要求。