简体   繁体   English

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

[英]Obtaining name of property without passing it in via reflection?

I'm trying to do something like this: 我正在尝试做这样的事情:

    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");
            }
        }
    }

So that I can use a pattern similar to this in my code base: 这样我就可以在我的代码库中使用与此类似的模式:

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

        // other processing here
    }

How do I know the name of the property which was passed in from the calling code inside of my validate method? 我如何知道从我的validate方法中的调用代码传入的属性的名称?

As Chris Sinclair mentioned, you can use LINQ expression, here is an example of such code: 正如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);
        }
    }
}

It's not directly possible, but there's a technique/hack that allows the retrieval of the parameter names by making them members of an anonymous type. 它不是直接可能的,但是有一种技术/黑客允许通过使它们成为匿名类型的成员来检索参数名称。

Based on your example, this is not a fit. 根据你的榜样,这是不是一个合适的。 It introduces unnecessary ambiguity and requires weakly typed method signature(s). 它引入了不必要的歧义,并且需要弱类型的方法签名。 It's also measurably slower than just passing the string name of the parameter in question. 它也比仅传递相关参数的字符串名称慢得多。

Again, don't use this for the stated purpose. 同样,不要将其用于所述目的。

Code

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

Output 产量

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

When might this pattern be appropriate? 这种模式什么时候适合?

It's worth noting that the ASP.Net MVC framework uses anonymous types extensively as a syntactic shortcut. 值得注意的是,ASP.Net MVC框架广泛使用匿名类型作为语法快捷方式。 The ComponentModel code comes straight from RouteValueDictionary . ComponentModel代码直接来自RouteValueDictionary

Simple answer: you can't. 简单回答:你做不到。

There are attributes in newer version of .NET that I thought would be helpful, but those don't look like they'd do the trick either. 在较新版本的.NET中有一些属性我认为会有所帮助,但那些看起来并不像他们那样做。

You can use Expression Tree to get names of parameters 您可以使用表达式树来获取参数的名称

    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"));
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM