从一个IQueryable <t>到一个IQueryable <myclass>中获取选定的T属性

时间:2018-07-18 11:19:02

标签: c# class generics iqueryable

我有一个泛型函数,其中包含一个IQueryable<T>,其中每一行都包含具有一组属性的类的实例。

我有另一个类(MyClass),它具有与上面的类T相同的某些属性……即,相同的名称和数据类型。

我还有一个字符串列表,其中包含两个类之间共享的属性名称。

我希望能够创建一个新的IQueryable<myClass>,在其中将myClass实例属性填充为原始IQueryable<T>中的名称属性

这有意义吗?请让我知道我是否可以提供更多信息或使任何事情变得更清楚。

编辑 我将尝试添加一些代码以更好地说明。我知道这里有无数的错误,包括添加到IQueryable中-但这只是为了说明:

IQueryable<T> qry = this.GetSomeDataIntoIQueryable();

// Just getting a list of the Shared Property Names between the two classes
List<string> sharedProprtyNames = new List<string>();
foreach (var item in ListofSharedPropertyNames)
{
    sharedProprtyNames .Add(item.SharedPropertyName);
}

IQueryable<myClass> myClassIQ;
foreach(var classItem in qry)
{
    myClass x = new myClass();
    foreach(var sharedProperty in sharedProprtyNames )
    {
        myClass[sharedProperty] = classItem[sharedProperty];
    }
    myClassIQ.Add(myClass);
}

2 个答案:

答案 0 :(得分:4)

类似的东西:

static IQueryable<TTo> Select<TFrom, TTo>(
     this IQueryable<TFrom> source,
     params string[] members)
{
    var p = Expression.Parameter(typeof(TFrom));
    var body = Expression.MemberInit(
        Expression.New(typeof(TTo)),
        members.Select(member => Expression.Bind(
            typeof(TTo).GetMember(member).Single(),
            Expression.PropertyOrField(p, member))));

    var lambda = Expression.Lambda<Func<TFrom, TTo>>(body, p);
    return source.Select(lambda);
}

这会创建一个IQueryable<T>TFrom的{​​{1}}友好投影,并尊重TTo中的所有成员。

在您的示例中,它将是:

members

(在{/ {1}}参数的数组/列表之间进行调整,以适合您的方便-因为我们使用IQueryable<myClass> myClassIQ = qry.Select<T, myClass>(ListofSharedPropertyNames); ,所以无论哪种都可以使用

答案 1 :(得分:3)

使用System.Linq.Dynamic.Core,您可以:

IQueryable<Table1> query1 = ...
var res = query.Select<SubTable1>("new(" + string.Join(",", new[] { "Col1", "Col2" }) + ")").ToArray();

其中query1是您的查询,Table1是问题的TSubTable1MyClass"Col1", "Col2"是必须选择。

您无需使用System.Linq.Dynamic.Core库就可以做任何事情,而只需构建一个表达式树...但这很痛苦:-)

我的Hans Passant代码的变体:

public static IQueryable<TResult> Select<TSource, TResult>(this IQueryable<TSource> source, IEnumerable<string> columns)
{
    // the x in x => ...
    var par = Expression.Parameter(typeof(TSource), "x");

    // "Bindings" (the Col1 = x.Col1 inside the x => new { Col1 = x.Col1 })
    var binds = columns.Select(x => Expression.Bind((MemberInfo)typeof(TResult).GetProperty(x) ?? typeof(TResult).GetField(x), Expression.PropertyOrField(par, x)));

    // new TResult
    var new1 = Expression.New(typeof(TResult));

    // new TResult { Bindings }
    var mi = Expression.MemberInit(new1, binds);

    // x => new TResult { Bindings }
    var lambda = Expression.Lambda<Func<TSource, TResult>>(mi, par);

    // Select(x => new TResult { Bindings })
    return source.Select(lambda);
}

(几乎完全等效……唯一的区别是他使用GetMember() + GetProperty()而我使用GetField()