C# 使用表达式创建强类型变量名列表
我有一门课:C# 使用表达式创建强类型变量名列表,c#,lambda,reflection,expression,expression-trees,C#,Lambda,Reflection,Expression,Expression Trees,我有一门课: public class Student { [JsonProperty("name")] public string Name { get; set; } [JsonProperty("age")] public int Age { get; set; } [JsonProperty("country")] public string Country { get; se
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;
}
公共静态列表PrintPropertyNames(参数表达式[]属性)
{
var list=新列表();
foreach(属性中的var p)
{
if(p.Body是MemberExpression)
{
var e=(MemberExpression)p.Body;
list.Add(((JsonPropertyAttribute)e.Member.GetCustomAttribute(typeof(JsonPropertyAttribute))).PropertyName);
}
其他的
{
var e=(MemberExpression)((一元表达式)p.Body)。操作数;
list.Add(((JsonPropertyAttribute)e.Member.GetCustomAttribute(typeof(JsonPropertyAttribute))).PropertyName);
}
}
退货清单;
}
我这样称呼它:
Console.WriteLine(string.Join(“,PrintPropertyNames(x=>x.Age,x=>x.Country))代码>
现在,我想修改我的方法定义,使其只接受一个参数,但我不知道如何做
我试过这样做:
公共静态列表PrintPropertyNames2(表达式[]属性)
我这样称呼它:
Console.WriteLine(string.Join(“,PrintPropertyNames2(新表达式[]{x=>x.Age,x=>x.Country}))代码>
我试图将其简化为:
Console.WriteLine(string.Join(“,PrintPropertyNames2(新[]{x=>x.Age,x=>x.Country}))代码>
但是编译器找不到最合适的类型。所以我必须显式地编写类型,它看起来很难看,而且不是我真正想要的。我需要它
在最终版本中,我要做的是:
Console.WriteLine(string.Join(“,PrintPropertyNames(x=>x.Age&&x.Country&&x.Name))代码>(输出应为-年龄国家/地区名称
)
我不确定这是否可行,但我想将所有属性放在一个表达式中,并立即获取它们的json属性值。对于初学者,不能使用x=>x.Age&&x.Country&&x.Name
-Age
是int
而Name
是字符串,并且不能将它们与和&
组合,因此会出现编译器错误。但是我们可以使用+
代替字符串浓缩,或者返回新的{x.Name,x.Age,x.Country}
或新对象[]{x.Name,x.Age,x.Country}
无论哪种方法,最简单的方法是使用查找所有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;
}
}
.对于初学者,您不能使用x=>x.Age&&x.Country&&x.Name
--Age
是一个int
,Name
是一个string
,您不能将它们与&
组合,因此您将得到一个编译器错误。但是我们可以使用+
代替字符串浓缩,或者返回新的{x.Name,x.Age,x.Country}
或新对象[]{x.Name,x.Age,x.Country}
无论哪种方法,最简单的方法是使用查找所有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;
}
}
.请注意,x=>x.Age&&x.Country&&x.Name
不是一个有效的表达式,它将编译--Age
是一个int
,Name
是一个字符串,你不能将它们与&
组合注意x.Age&&x.Country&&x.Name
不是一个有效的表达式,它将编译--Age
是一个int
和Name
是一个字符串
,你不能将它们与&
组合,我认为FindPropertyNames(x=>新{x.Name,x.Age,x.Country});
一个更好看的用法。@GuruStron Fair point!作为示例添加进来(代码按原样工作)@canton7非常好的答案,谢谢。但是,我必须注意,带plus(最后一个)-(x=>x.Name+x.Age+x.Country)的语法
如果存在类类型,则不起作用。例如,如果Age
是public CustomAge{get;set;}
,它不起作用。@Axajkamkat在您的特定示例中,它会起作用,因为string+anything=string
。如果没有将字符串作为前两个内容之一合并在一起,它将不起作用。但是:您必须添加一个空字符串“”
一开始,我很喜欢Guruston关于匿名对象的建议:没错,我也使用过匿名对象。但是我在我的类中添加了更多属性,其中一个是另一个类属性,正如你所说,它不能与字符串concat一起正常工作。不管怎样,解决方案都非常优雅,谢谢,感谢!我认为FindPropertyNames(x=>new{x.Name,x.Age,x.Country});
是一个更好看的用法。@GuruStron Fair point!作为示例添加进来(代码按原样工作)@canton7非常好的答案,谢谢。不过,我必须注意,带plus(最后一个)(x=>x.Name+x.Age+x.Country)的语法
如果存在类类型,则不起作用。例如,如果Age
是public CustomAge{get;set;}
,它不起作用。@Axajkamkat在您的特定示例中,它会起作用,因为string+anything=string
。如果没有将字符串作为前两个内容之一合并在一起,它将不起作用。但是:您必须添加一个空字符串“”
一开始,我很喜欢Guruston关于匿名对象的建议:没错,我也使用过匿名对象。但是我在我的类中添加了更多属性,其中一个是另一个类属性,正如你所说,它不能与字符串concat一起正常工作。不管怎样,解决方案都非常优雅,谢谢,谢谢你!
var names = FindPropertyNames<Student>(x => new { x.Name, x.Age, x.Country });
var names = FindPropertyNames<Student>(x => new object[] { x.Name, x.Age, x.Country });
var names = FindPropertyNames<Student>(x => x.Name + x.Age + x.Country);