3

我正在尝试做这样的事情:

    public static class Validate
    {
        public static void AgainstNull(string str)
        {
            if (String.IsNullOrWhiteSpace(str))
            {
                // how do I know the property name in the calling code?
                throw new ArgumentNullException("property name from caller");
            }
        }
    }

这样我就可以在我的代码库中使用与此类似的模式:

    public void Foo(string bar)
    {
        Validate.AgainstNull(bar);

        // other processing here
    }

我如何知道从我的 validate 方法中的调用代码传入的属性的名称?

4

4 回答 4

3

正如 Chris Sinclair 所提到的,您可以使用 LINQ 表达式,下面是此类代码的示例:

public static class Validate
{
    public static void AgainstNull(System.Linq.Expressions.Expression<Func<string>> expr)
    {
        var str = expr.Compile().Invoke();
        if (str == null)
        {
            string name = (expr.Body as System.Linq.Expressions.MemberExpression).Member.Name;
            throw new ArgumentNullException(name);
        }
    }
}
于 2013-11-12T22:59:36.803 回答
2

这不是直接可能的,但是有一种技术/黑客可以通过使参数名称成为匿名类型的成员来检索参数名称。

根据您的示例,这不合适。它引入了不必要的歧义,并且需要弱类型的方法签名。它也比仅传递相关参数的字符串名称要慢得多。

同样,不要将其用于所述目的。

代码

void Main()
{
    Foo( "hello", "world", 123, false );
}

private static void Foo( string bar, string baz, int abc, bool xyz )
{
    Evaluate( new { bar, baz, abc, xyz } );
}

private static void Evaluate( object o )
{
    var properties = System.ComponentModel.TypeDescriptor.GetProperties( o );
    foreach( System.ComponentModel.PropertyDescriptor propertyDescriptor in properties )
    {
        var value = propertyDescriptor.GetValue( o );
        Console.WriteLine( "Name: {0}, Value: {1}", propertyDescriptor.Name, value );
    }
}

输出

Name: bar, Value: hello
Name: baz, Value: world
Name: abc, Value: 123
Name: xyz, Value: False

这种模式什么时候合适?

值得注意的是,ASP.Net MVC 框架广泛使用匿名类型作为语法快捷方式。ComponentModel代码直接来自RouteValueDictionary.

于 2013-11-12T23:00:02.617 回答
1

简单的答案:你不能。

在较新版本的 .NET 中有一些我认为会有所帮助的属性,但这些属性看起来也不会起到作用。

于 2013-11-12T22:36:06.117 回答
0

您可以使用表达式树来获取参数的名称

    public static class Validate
    {
        public static void AgainstNull(string str)
        {
            if (String.IsNullOrWhiteSpace(str))
            {
                var parametersNames = GetParameterNames(() => AgainstNull(str));
                throw new ArgumentNullException(parametersNames[0]);
            }
        }

        private static string[] GetParameterNames(Expression<Action> expression)
        {
            var methodInfo = ((MethodCallExpression)expression.Body).Method;
            var names = methodInfo.GetParameters().Select(p => p.Name);
            return names.ToArray();
        }
    }

    [Fact]
    public void AgainstNullTest()
    {
        var ex = Assert.Throws<ArgumentNullException>(() => Validate.AgainstNull(string.Empty));

        Assert.True(ex.Message.EndsWith("str"));
    }
于 2013-11-12T23:01:32.353 回答