正在评估 select 投影
Evaluating select projection
是否可以在某个时候评估 select 投影以获得正在 selected 的属性列表?
例如,如果我有以下 class:
public class Example()
{
public string Aaa { get; set; }
public int Bbb { get; set; }
public string Ccc { get; set; }
}
和以下 select 投影:
Expression<Func<Example, Example>> select = x => new Example { Aaa= x.Aaa, Ccc = x.Ccc };
是否可以解释 select 投影以获得与 var result = new List<string> { "Aaa", "Ccc" };
一致的结果?
执行此类操作的最佳方法是使用 ExpressionVisitor
。
这是一个例子:
public class MyMemberExpressionVisitor : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType == MemberTypes.Property // is a property
&& node.Expression.NodeType == ExpressionType.Parameter // is from a parameter expression
&& Members.All(s => s != node.Member.Name)) // avoids duplicates
{
Members.Add(node.Member.Name);
}
return base.VisitMember(node);
}
public List<string> Members { get; set; } = new List<string>();
}
那么你可以这样使用它:
// Complex expressions work too!
Example outsideExample = new Example();
Expression<Func<Example, Example>> expression = x => new Example(
x.Aaa + outsideExample.Bbb,
x.Ccc + x.Aaa.Length);
var myVisitor = new MemberExpressionVisitor();
myVisitor.Visit(expression);
Console.WriteLine(string.Join(", ", myVisitor.Members)); // This should print out "Aaa, Ccc"
您可以访问 How to: Implement an Expression Tree Visitor 了解更多关于如何实施的信息。
要查找该表达式中的所有 属性 表达式,您可以使用 ExpressionVisitor
检查给定表达式中的所有 Expression
实例并查看哪些是 属性 访问,以及 属性 正在访问的内容:
internal class PropertySearchVisitor : ExpressionVisitor
{
private List<MemberInfo> properties = new List<MemberInfo>();
public IEnumerable<MemberInfo> Properties => properties;
protected override Expression VisitMember(MemberExpression node)
{
if (node?.Member?.MemberType == MemberTypes.Property)
properties.Add(node.Member);
return base.VisitMember(node);
}
}
一旦你有了它,你就可以编写一个方法来访问给定的表达式和 return 该表达式的属性(或 属性 名称):
public static IEnumerable<MemberInfo> GetProperties(this Expression expression)
{
var visitor = new PropertySearchVisitor();
visitor.Visit(expression);
return visitor.Properties;
}
public static IEnumerable<string> GetPropertyNames(this Expression expression)
{
var visitor = new PropertySearchVisitor();
visitor.Visit(expression);
return visitor.Properties.Select(property => property.Name);
}
是否可以在某个时候评估 select 投影以获得正在 selected 的属性列表?
例如,如果我有以下 class:
public class Example()
{
public string Aaa { get; set; }
public int Bbb { get; set; }
public string Ccc { get; set; }
}
和以下 select 投影:
Expression<Func<Example, Example>> select = x => new Example { Aaa= x.Aaa, Ccc = x.Ccc };
是否可以解释 select 投影以获得与 var result = new List<string> { "Aaa", "Ccc" };
一致的结果?
执行此类操作的最佳方法是使用 ExpressionVisitor
。
这是一个例子:
public class MyMemberExpressionVisitor : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType == MemberTypes.Property // is a property
&& node.Expression.NodeType == ExpressionType.Parameter // is from a parameter expression
&& Members.All(s => s != node.Member.Name)) // avoids duplicates
{
Members.Add(node.Member.Name);
}
return base.VisitMember(node);
}
public List<string> Members { get; set; } = new List<string>();
}
那么你可以这样使用它:
// Complex expressions work too!
Example outsideExample = new Example();
Expression<Func<Example, Example>> expression = x => new Example(
x.Aaa + outsideExample.Bbb,
x.Ccc + x.Aaa.Length);
var myVisitor = new MemberExpressionVisitor();
myVisitor.Visit(expression);
Console.WriteLine(string.Join(", ", myVisitor.Members)); // This should print out "Aaa, Ccc"
您可以访问 How to: Implement an Expression Tree Visitor 了解更多关于如何实施的信息。
要查找该表达式中的所有 属性 表达式,您可以使用 ExpressionVisitor
检查给定表达式中的所有 Expression
实例并查看哪些是 属性 访问,以及 属性 正在访问的内容:
internal class PropertySearchVisitor : ExpressionVisitor
{
private List<MemberInfo> properties = new List<MemberInfo>();
public IEnumerable<MemberInfo> Properties => properties;
protected override Expression VisitMember(MemberExpression node)
{
if (node?.Member?.MemberType == MemberTypes.Property)
properties.Add(node.Member);
return base.VisitMember(node);
}
}
一旦你有了它,你就可以编写一个方法来访问给定的表达式和 return 该表达式的属性(或 属性 名称):
public static IEnumerable<MemberInfo> GetProperties(this Expression expression)
{
var visitor = new PropertySearchVisitor();
visitor.Visit(expression);
return visitor.Properties;
}
public static IEnumerable<string> GetPropertyNames(this Expression expression)
{
var visitor = new PropertySearchVisitor();
visitor.Visit(expression);
return visitor.Properties.Select(property => property.Name);
}