如何解决使用表达式创建强类型变量名称列表
我有一堂课:
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
-- Age
是 int
和 Name
是 string
,并且您不能组合那些带有 &&
的,所以你会得到一个编译器错误。但是我们可以使用 +
代替字符串连接,或者返回 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);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。