将选定的 T 属性从一个 IQueryable<T> 获取到一个 IQueryable<MyClass>

Get Selected T proprties from one IQueryable<T> into an IQueryable<MyClass>

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

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

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

我希望能够创建一个新的 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);
}

使用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()

类似于:

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);
}

?

这会创建一个从 TFromTToIQueryable<T> 友好投影,尊重 members 的所有成员。

在您的示例中,它将是:

IQueryable<myClass> myClassIQ = qry.Select<T, myClass>(ListofSharedPropertyNames);

(在 members 参数的数组/列表之间进行调整以方便您使用 - 因为我们使用 Select,它可以与任何一个一起使用)