使用Lambda表达式获取属性名称和类型

40
我想编写一个函数,使用以下语法来提取属性名称和类型:
private class SomeClass
{
    Public string Col1;
}

PropertyMapper<Somewhere> propertyMapper = new PropertyMapper<Somewhere>();
propertyMapper.MapProperty(x => x.Col1)

有没有一种方法可以在不对此语法进行重大更改的情况下将属性传递给函数?

我想获取属性名和属性类型。

因此,在下面的示例中,我想要检索

Name =“Col1”Type =“System.String”

有人能帮忙吗?


什么是更大的画面?为什么不只是将“Col1”作为字符串名称传递并使用反射来查找该成员?是什么激发了Lambda表达式的动机? - Brian
12
我正在为我的工作编写一个内部 ORM。我希望能够轻松支持更改属性名称,而不必到处查找字符串,这样可以使语法看起来更清晰(在我看来)。 - pythonandchips
这个回答解决了你的问题吗?从Lambda表达式中检索属性名称 - Luiso
4个回答

66

以下是使用表达式获取属性或字段名称的示例:

public static MemberInfo GetMemberInfo<T, U>(Expression<Func<T, U>> expression)
{
    var member = expression.Body as MemberExpression;
    if (member != null)
        return member.Member;

    throw new ArgumentException("Expression is not a member access", "expression");
}

调用代码将如下所示:
public class Program
{
    public string Name
    {
        get { return "My Program"; }
    }

    static void Main()
    {
        MemberInfo member = ReflectionUtility.GetMemberInfo((Program p) => p.Name);
        Console.WriteLine(member.Name);
    }
}

但是需要注意的是:简单的语句(Program p) => p.Name实际上涉及到相当多的工作(并且可能需要一定的时间)。考虑缓存结果而不是频繁调用该方法。


6
请记住 lambda 表达式可以转换为委托(delegate)或表达式树(expression tree)。 - Jon Skeet
1
警告:GetMemberInfo实现不太安全 - https://dev59.com/HGw15IYBdhLWcg3wYKmo。尽管如此,您仍可以使用它来读取名称。但是返回的成员信息本身不准确。 - nawfal

4

这可以很容易地在C# 6中完成。使用nameof运算符获取属性名称。

nameof(User.UserId)

使用typeof运算符来获取属性的类型。

typeof(User.UserId)

3

我认为把这个放在这里可以对之前的方法进行补充。

public static class Helpers
{
    public static string PropertyName<T>(Expression<Func<T>> expression)
    {
        var member = expression.Body as MemberExpression;
        if (member != null && member.Member is PropertyInfo)
            return member.Member.Name;

        throw new ArgumentException("Expression is not a Property", "expression");
    }
}

您可以按照以下方式调用它:
Helpers.PropertyName(() => TestModel.TestProperty);

我应该指出,在使用VS 2015和C# 6.0时,您可以简单地使用nameof。

https://msdn.microsoft.com/en-us/library/dn986596.aspx


3
我发现这非常有用。
public class PropertyMapper<T>
{
    public virtual PropertyInfo PropertyInfo<U>(Expression<Func<T, U>> expression)
    {
        var member = expression.Body as MemberExpression;
        if (member != null && member.Member is PropertyInfo)
            return member.Member as PropertyInfo;

        throw new ArgumentException("Expression is not a Property", "expression");
    }

    public virtual string PropertyName<U>(Expression<Func<T, U>> expression)
    {
        return PropertyInfo<U>(expression).Name;
    }

    public virtual Type PropertyType<U>(Expression<Func<T, U>> expression)
    {
        return PropertyInfo<U>(expression).PropertyType;
    }
}

我写了这个小类以满足原始请求。 如果你需要属性的名称,可以像这样使用它:
PropertyMapper<SomeClass> propertyMapper = new PropertyMapper<SomeClass>();
string name = propertyMapper.PropertyName(x => x.Col1);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接