如何创建一个动态的多属性上一个IEnumerable&LT选择; T>在运行时? [英] How can I create a dynamic multi-property Select on an IEnumerable<T> at runtime?

查看:204
本文介绍了如何创建一个动态的多属性上一个IEnumerable&LT选择; T>在运行时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问一个非常相似问题昨天,但它不是直到今天我才意识到我接受并不能解决我的所有问题的答案。我有以下代码:

 公共表达式来; Func键< TItem,对象>> SelectExpression< TItem>(串字段名)
{
VAR参数= Expression.Parameter(typeof运算(TItem),项目);
VAR字段= Expression.Property(参数,字段名);
返回Expression.Lambda<&Func键LT; TItem,对象>>(场,
新ParameterExpression [] {参数});
}



这是作为如下:

 字符串的PrimaryKey = _map.GetPrimaryKeys(typeof运算(TOriginator))单(); 
VAR primaryKeyExpression = SelectExpression< TOriginator>(PrimaryKey的);
VAR primaryKeyResults = query.Select(pr​​imaryKeyExpression).ToList();

这让我从的IQueryable<拉出主键; TUnknown> 。问题是,这个代码只用一个主键和工作我需要添加多种的PK支持。



那么,有没有什么办法可以适应上述 SelectExpression 方法采取 IEnumerable的<串> (这是我的主键的属性名的列表),并有该方法返回选择这些键



Ie的表达?鉴于以下内容:

  VAR knownRuntimePrimaryKeys =新的String [] {客户编号,的OrderId}`

我的选择需要做以下(在运行时):

  VAR primaryKeys = query.Select(X =>新建{x.Cu​​stomerId,x.OrderId}); 


解决方案

有没有简单的方法做的正是你想要什么,因为这需要你来动态地创建一个新的类型(匿名类型由编译器创建时,他们静态已知)。虽然这肯定是可行的,它可能不是最简单的选项...



您可以实现使用类似结果的元组

 公共表达式来; Func键< TItem,对象>> SelectExpression< TItem>(字符串[] propertyNames)
{
VAR性能= propertyNames.Select(名称=> typeof运算(TItem).GetProperty(名))。ToArray的();
VAR propertyTypes = properties.Select(P => p.PropertyType).ToArray();
VAR tupleTypeDefinition = typeof运算(数组).Assembly.GetType(System.Tuple`+ properties.Length);
VAR tupleType = tupleTypeDefinition.MakeGenericType(propertyTypes);
VAR构造= tupleType.GetConstructor(propertyTypes);
VAR参数= Expression.Parameter(typeof运算(TItem),项目);
变种体= Expression.New(构造函数,properties.Select(P => Expression.Property(参数,P)));
VAR EXPR = Expression.Lambda<&Func键LT; TItem,对象>>(机身,参数);
返回expr的;
}


I asked a very similar question yesterday, but it wasn't until today I realised the answer I accepted doesn't solve all my problems. I have the following code:

public Expression<Func<TItem, object>> SelectExpression<TItem>(string fieldName)
{
    var param = Expression.Parameter(typeof(TItem), "item");
    var field = Expression.Property(param, fieldName);
    return Expression.Lambda<Func<TItem, object>>(field, 
        new ParameterExpression[] { param });
}

Which is used as follows:

string primaryKey = _map.GetPrimaryKeys(typeof(TOriginator)).Single();
var primaryKeyExpression = SelectExpression<TOriginator>(primaryKey);
var primaryKeyResults = query.Select(primaryKeyExpression).ToList();

This allows me to pull out the primary keys from an IQueryable<TUnknown>. The problem is that this code only works with a single primary key and I need to add support for multiple PKs.

So, is there any way I can adapt the SelectExpression method above to take an IEnumerable<string> (which is my list of primary key property names) and have the method return an expression that selects those keys?

I.e. Given the following:

var knownRuntimePrimaryKeys = new string[] { "CustomerId", "OrderId" }`

My Select needs to do the following (at runtime):

var primaryKeys = query.Select(x=> new { x.CustomerId, x.OrderId });

解决方案

There is no easy way to do exactly what you want, because it would require you to create a new type dynamically (anonymous types are created by the compiler when they're known statically). While it is certainly feasible, it's probably not the easiest option...

You can achieve a similar result using tuples:

public Expression<Func<TItem, object>> SelectExpression<TItem>(string[] propertyNames)
{
    var properties = propertyNames.Select(name => typeof(TItem).GetProperty(name)).ToArray();
    var propertyTypes = properties.Select(p => p.PropertyType).ToArray();
    var tupleTypeDefinition = typeof(Tuple).Assembly.GetType("System.Tuple`" + properties.Length);
    var tupleType = tupleTypeDefinition.MakeGenericType(propertyTypes);
    var constructor = tupleType.GetConstructor(propertyTypes);
    var param = Expression.Parameter(typeof(TItem), "item");
    var body = Expression.New(constructor, properties.Select(p => Expression.Property(param, p)));
    var expr = Expression.Lambda<Func<TItem, object>>(body, param);
    return expr;
}

这篇关于如何创建一个动态的多属性上一个IEnumerable&LT选择; T&GT;在运行时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆