获取属性名称而不通过反射传递它?

时间:2013-11-12 22:29:20

标签: c# reflection

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

    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 个答案:

答案 0 :(得分: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);
        }
    }
}

答案 1 :(得分: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

答案 2 :(得分:1)

简单回答:你做不到。

我认为在较新版本的.NET中有attributes会有所帮助,但看起来他们也不会这样做。

答案 3 :(得分: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"));
    }