将属性作为函数参数传递,并将其名称转换为字符串内部

时间:2016-08-03 17:06:59

标签: c# reflection nameof

我希望能够将任何可能的类型作为函数参数传递。

现在,传递属性存在问题,例如。

class Foo
{
    public int Bar { get; set; }
}

我可以使用: nameof(Foo.Bar) 但我无法做A(Foo.Bar)在A中将使用nameof。

我想确保字符串是从属性创建的,我希望将属性传递给API并在API中进行名称。

是否有可能通过函数将属性传递给nameof?我想隐藏属性转换为我的类内部的字符串而不是准备好字符串。如何实现?

编辑:线索是关于:

class B
{
    public Prop {get; set;}
}

void foo([?])
{
    Console.WriteLine(nameof([?]));
}

代替[?]使控制台输出如:Prop。

2 个答案:

答案 0 :(得分:1)

我认为你在这里解释nameof有点不对。

在您的第一个示例中,该方法将始终打印T,并且不依赖于T的类型。 nameof关键字除了用表达式的字符串表示替换给它的表达式外什么都不做。例如我们提供nameof参数T,他将返回该表达式的字符串表示形式:T

void A<T>(T smth)
{
   Console.Writeline(nameof(T)); // example usage
}

一般来说,nameof的用法是为方法提供可重构的方法/属性/ ...名称。

例如,ArgumentOutOfRangeException具有参数名称​​超出范围作为参数。

void Test(int value)
{
    if (value < 0) throw new ArgumentOutOfRangeException("value");
    // yada yada
}

如果我们将名称提供为上面示例中的硬编码字符串,则在重命名参数时会出现不一致。

为了解决这个问题,我们使用nameof,因为我们提供参数本身而不是硬编码字符串,所以它是重构安全的。

void Test(int value)
{
    if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
    // yada yada
}

答案 1 :(得分:1)

c#编译器在编译时使用'nameof'来查找和替换事物,因此它不会像你期望的那样工作。相反,您需要使用表达式或反射在运行时获取属性的名称。 以下是使用表达式执行此操作的示例:

public static string GetName<T>(Expression<Func<T>> expression)
    {
        var member = (MemberExpression)expression.Body;
        return member.Member.Name;
    }
    public static string GetName<T>(Expression<Func<T, object>> expression)
    {
        var body = expression.Body as MemberExpression;

        if (body == null)
        {
            body = ((UnaryExpression)expression.Body).Operand as MemberExpression;
        }

        return body.Member.Name;
    }

    public static void PrintName<T>(Expression<Func<T>> expression)
    { 
        Console.WriteLine(GetName(expression));
    }

    public static void PrintName<T>(Expression<Func<T, object>> expression)
    { 
        Console.WriteLine(GetName(expression));
    }

像这样使用:

class B
{
    public Prop {get; set;}
}

static void Main(string[] args)
    { 
        PrintName<B>((b) => b.Prop); 

        //Or
        var someObject = new B();
        PrintName(() => someObject.Prop); 

        Console.ReadLine();
    }