微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用表达式创建强类型变量名称列表

如何解决使用表达式创建强类型变量名称列表

我有一堂课:

public class Student
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("age")]
    public int Age { get; set; }

    [JsonProperty("country")]
    public string Country { get; set; }
}

我有一个方法

public static List<string> PrintPropertyNames<T>(params Expression<Func<T,object>>[] properties)
{
    var list = new List<string>();

    foreach (var p in properties)
    {
        if (p.Body is MemberExpression)
        {
            var e = (MemberExpression)p.Body;
            list.Add(((JsonPropertyAttribute)e.Member.GetCustomAttribute(typeof(JsonPropertyAttribute))).PropertyName);
        }
        else
        {
            var e = (MemberExpression)((UnaryExpression)p.Body).Operand;
            list.Add(((JsonPropertyAttribute)e.Member.GetCustomAttribute(typeof(JsonPropertyAttribute))).PropertyName);
        }
    }

    return list;
}

我这样称呼:

Console.WriteLine(string.Join(" ",PrintPropertyNames<Student>(x => x.Age,x => x.Country)));

现在,我想修改我的方法定义以只接受一个参数,但我不知道该怎么做。

我尝试做这样的事情:

public static List<string> PrintPropertyNames2<T>(Expression<Func<T,object>>[] properties)

我这样称呼:

Console.WriteLine(string.Join(" ",PrintPropertyNames2<Student>(new Expression<Func<Student,object>>[] { x => x.Age,x => x.Country })));

我尝试将其简化为:

Console.WriteLine(string.Join(" ",PrintPropertyNames2<Student>(new [] { x => x.Age,x => x.Country })));

但是编译器找不到最合适的类型。所以我必须明确地编写类型,它看起来很难看,而且无论如何都不是我真正想要的。我需要通用的。

我想在最终版本中做的是:

Console.WriteLine(string.Join(" ",PrintPropertyNames<Student>(x => x.Age && x.Country && x.Name)));输出应该是 - age country name

我不确定这是否可行,但我想将所有属性放在一个表达式中并立即获取它们的 json 属性值。

解决方法

对于初学者,您不能使用 x => x.Age && x.Country && x.Name -- AgeintNamestring,并且您不能组合那些带有 && 的,所以你会得到一个编译器错误。但是我们可以使用 + 代替字符串连接,或者返回 new { x.Name,x.Age,x.Country }new object[] { x.Name,x.Country }

无论哪种方式,最简单的方法是使用 ExpressionVisitor 查找访问我们输入 MemberAccess 上的属性的所有 Student 表达式,无论它们埋在表达:

public class FindPropertiesVisitor : ExpressionVisitor
{
    private readonly Expression parameter;
    public List<string> Names { get; } = new List<string>();

    public FindPropertiesVisitor(Expression parameter) => this.parameter = parameter;

    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.Expression == parameter)
        {
            Names.Add(node.Member.GetCustomAttribute<JsonPropertyAttribute>().PropertyName);
        }
        return node;
    }
}

使用它非常简单:

public static List<string> FindPropertyNames<T>(Expression<Func<T,object>> expr)
{
    var visitor = new FindPropertiesVisitor(expr.Parameters[0]);
    visitor.Visit(expr);
    return visitor.Names;
}

我们传入 expr.Parameters[0] 作为 Student 表达式,我们希望在其上查找成员访问。

然后您可以使用任何以任何方式访问这些属性的表达式调用它,例如:

var names = FindPropertyNames<Student>(x => new { x.Name,x.Country });
var names = FindPropertyNames<Student>(x => new object[] { x.Name,x.Country });
var names = FindPropertyNames<Student>(x => x.Name + x.Age + x.Country);

See it working here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。