如何在LINQ表达式中选择多个类属性?

时间:2018-02-19 15:04:40

标签: linq lambda

如果我有这样的课程

`
  class Person
  {
    public string First;
    public string Last;
    public bool IsMarried;
    public int Age;
  }`

那么如何编写LINQ表达式,我可以在其中选择Person的属性。我想做这样的事情(用户可以输入1..n属性)

SelectData<Person>(x=>x.First, x.Last,x.Age);

我的SelectData函数的输入表达式是什么?

SelectData(Expression<Func<TEntity, List<string>>> selector); ?

修改 在我的SelectData函数中,我想提取属性名,然后动态生成我的SQL查询的SELECT子句。

好的,我所做的就是将我的SelectData作为

public IEnumerable<TEntity> SelectData(Expression<Func<TEntity, object>> expression)
    {
        NewExpression body = (NewExpression)expression.Body;
        List<string> columns = new List<string>();
        foreach(var arg in body.Arguments)
        {
            var exp = (MemberExpression)arg;
            columns.Add(exp.Member.Name);
        }
        //build query

使用它我称之为

ccc<Person>().SelectData(x => new { x.First, x.Last, x.Age });

希望它会帮助那些正在寻找的人:)

谢谢, IY

2 个答案:

答案 0 :(得分:0)

您可以使用ReflectionExtension Method

获得类似的结果

型号:

namespace ConsoleApplication2
{
    class Person
    {
        public string First { get; set; }
        public string Last { get; set; }
        public bool IsMarried { get; set; }
        public int Age { get; set; }
    }
}

服务:

using System.Collections.Generic;
using System.Linq;

namespace Test
{
    public static class Service
    {
        public static IQueryable<IQueryable<KeyValuePair<string, object>>> SelectData<T>(this IQueryable<T> queryable, string[] properties)
        {
            var queryResult = new List<IQueryable<KeyValuePair<string, object>>>();
            foreach (T entity in queryable)
            {
                var entityProperties = new List<KeyValuePair<string, object>>();
                foreach (string property in properties)
                {
                    var value = typeof(T).GetProperty(property).GetValue(entity);
                    var entityProperty = new KeyValuePair<string, object>(property, value);
                    entityProperties.Add(entityProperty);
                }
                queryResult.Add(entityProperties.AsQueryable());
            }
            return queryResult.AsQueryable();
        }
    }
}

用法:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var list = new List<Person>()
            {
                new Person()
                {
                    Age = 18,
                    First = "test1",
                    IsMarried = false,
                    Last = "test2"
                },
                new Person()
                {
                    Age = 40,
                    First = "test3",
                    IsMarried = true,
                    Last = "test4"
                }
            };

            var queryableList = list.AsQueryable();
            string[] properties = { "Age", "Last" };
            var result = queryableList.SelectData(properties);

            foreach (var element in result)
            {
               foreach (var property in element)
                {
                    Console.WriteLine($"{property.Key}: {property.Value}");
                }
            }
            Console.ReadKey();
        }
    }
}

结果:

Age: 18
Last: test2
Age: 40
Last: test4

答案 1 :(得分:0)

我认为使用委托而不是反射会更好。除了委托更快的事实之外,如果您尝试获取不存在的属性值,编译器会抱怨。使用反射,在运行时之前不会发现错误。

幸运的是,已经有类似的东西了。它被实现为IEnumerable的扩展函数,它被称为Select(具有讽刺意味)

我想你想要这样的东西:

  

我有一系列人员,我希望你创建一个Linq   每个Person返回一个包含该对象的新对象的语句   属性第一和最后。

或者:

  

我有一系列Persns,我希望你创建一个Linq语句   每个Person返回一个包含Age,IsMarried的新对象,   是否是一个成年人并使其变得困难:一个财产叫做   名称是First和Last的组合

函数SelectData将是这样的:

IEnumerable<TResult> SelectData<TSource, TResult>(this IEnumerable<TSource> source,
    Func<TSource, TResult> selector)
{
    return source.Select(selector);
}

用法:

问题1:每个人返回一个包含该对象的新对象 属性第一和最后。

var result = Persons.SelectData(person => new
{
    First = person.First,
    Last = person.Last,
});

问题2:每个人返回一个包含Age,IsMarried的新对象,他是否是一个成年人和一个名为Name的属性,它是一个组合 第一个和最后一个

var result = Persons.SelectData(person => new
{
    Age = person.Name,
    IsMarried = person.IsMarried,
    IsAdult = person.Age > 21,

    Name = new 
    {
        First = person.First,
        Last = person.Last,
    },
});

让我们面对现实吧,你的SelectData只不过是Enumerable.Select

你当然可以创建一个函数,你可以让调用者提供他想要的属性列表,但是(1)这将限制他设计最终结果的可能性,以及(2)它会更多地输入他打电话给这个职能部门。

而不是:

.Select(p => new
{
    P1 = p.Property1,
    P2 = p.Property2,
}

他必须键入类似

的内容
.SelectData(new List<Func<TSource, TResult>()
{
     p => p.Property1,     // first element of the property list
     p -> p.Property2,     // second element of the property list
}

您将无法命名返回的属性,您将无法将多个属性合并为一个:

.Select(p => p.First + p.Last)

你会从中获得什么?

非常沮丧的要求!