我有以下LINQ表达式:
var query = entities
.Select(e => new MyObject()
{
Property1 = e.Item1,
Property2 = e.Item2
});
MyObject可能还有Property3,Property4已定义。我需要通过表达式visitor来了解哪些属性是LINQ投影的一部分。
所以我称之为:
var listOfProperties = query.GetSelectedPropertyNames();
并且listOfProperties的内容将是包含Property1, Property2
的字符串数组或我可以检查的内容:
var isPropertyInProjection = query.HasPropertyInProjection(nameof(MyObject.Property3));
,结果将是假的。
答案 0 :(得分:1)
您可以使用ExpressionVisitor
轻松完成此操作。只需创建一个新类并覆盖访问方法。如果您知道投影是使用成员绑定完成的,则可以简单地覆盖方法VisitMemberBinding
并将绑定成员添加到存储为实例变量的列表中。然后,您需要做的就是将该实例变量设为公共。
class ProjectionAnalyzer : ExpressionVisitor
{
private HashSet<MemberInfo> boundMembers = new HashSet<MemberInfo>();
protected override MemberBinding VisitMemberBinding(MemberBinding node)
{
boundMembers.Add(node.Member);
return base.VisitMemberBinding(node);
}
public IEnumerable<MemberInfo> BoundMembers => boundMembers;
}
然后,按如下方式使用此类:
var analyzer = new ProjectionAnalyzer();
analyzer.Visit(selectorPredicate);
var boundMembers = analyzer.BoundMembers;
如何获取选择器谓词取决于您的LINQ提供程序。
答案 1 :(得分:1)
我使用VisitMemberAssignment做了类似的事情:
namespace BoundPropertiesinQuery
{
static class IEnumerableExtensions
{
class ProjectedVisitor : ExpressionVisitor
{
public IList<string> ProjectedPropertyNames { get; set; } = new List<string>();
protected override MemberAssignment VisitMemberAssignment(MemberAssignment node)
{
ProjectedPropertyNames.Add(node.Member.Name);
return base.VisitMemberAssignment(node);
}
}
public static IEnumerable<string> ProjectedProperties<T>(this IQueryable<T> @this)
{
var pv = new ProjectedVisitor();
pv.Visit(@this.Expression);
return pv.ProjectedPropertyNames.Distinct();
}
}
internal class MyObject
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public int Property3 { get; set; }
public int Property4 { get; set; }
}
internal class MyOtherObject
{
public int other1 { get; set; }
public int other2 { get; set; }
public int other3 { get; set; }
public int other4 { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
var listOfItems = new List<MyOtherObject>()
{
new MyOtherObject
{
other1 = 1,
other2 = 2,
other3 = 3,
other4 = 4
},
new MyOtherObject
{
other1 = 5,
other2 = 6,
other3 = 7,
other4 = 8
}
};
var result = listOfItems.AsQueryable().Select(m => new MyObject
{
Property1 = m.other1,
Property2 = m.other2
}).ProjectedProperties();
foreach (var item in result)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
}
}