获取LINQ投影中的属性列表

时间:2018-02-01 10:43:42

标签: c# linq

我有以下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));

,结果将是假的。

2 个答案:

答案 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();
        }
    }
}