7

我有一个IQuerable<object> source对象,必须从中得到类似的东西(但使用反射)。

source.Select(t => new SelectListItem { Name = t.Name, Value = t.Id })

我该怎么做,或者我在哪里可以找到构建这种表达式树的参考。

谢谢

4

2 回答 2

12

您可以使用命名空间 ( MSDN )创建ExpressionsSystem.Linq.Expressions

在您的情况下,它看起来像这样:

var source = typeof( Source );
var target = typeof( SelectListItem );

var t = Expression.Parameter( source, "t" );

var sourceName = Expression.MakeMemberAccess( t, source.GetProperty( "Name" ) );
var sourceId = Expression.MakeMemberAccess( t, source.GetProperty( "Id" ) );

var assignName = Expression.Bind( target.GetProperty( "Name" ), sourceName );
var assignValue = Expression.Bind( target.GetProperty( "Value" ), sourceId );
var targetNew = Expression.New( target );
var init = Expression.MemberInit( targetNew, assignName, assignValue );

var lambda =
  ( Expression<Func<Source,SelectListItem>> ) Expression.Lambda( init, t );

你可以像这样使用它:

IQueryable<Source> list = ...

List<SelectListItem> items = list.Select( lambda ).ToList();
于 2013-01-11T10:20:37.217 回答
0

在运行时知道哪些类型信息(如果有)有点不清楚。捎带Nicholas Butler 的回答(因为它已被接受)让我们假设您将“知道”源类型(即 IQueryable 源中 T 的类型是什么)并且您将“知道”目标类型(从IQueryable.Select 扩展方法)。当我说“知道”时,我的意思是它可以在运行时发现而无需动态、反射、后期绑定等。否则,他的解决方案只有在源和目标类型恰好具有具有这些匹配名称的属性时才有效(即“名称/ID”和“名称/值”)。

鉴于此,有一个非常简单的解决方案,无需手动构造您的 lambda 表达式......

解决方案:首先让我们定义这两种类型,以便我们知道我们正在处理什么。我这样做只是因为我不知道您使用的是什么类型,所以这些确实是您实际使用的占位符,因此您的解决方案不需要这,仅用于演示/示例目的:

//this is whatever your source item type is (t) 
public class NameIdPair
{
    public string Name { get; set; }

    public string Id { get; set; }
}

//this is whatever the SelectListItem type is you're using
public class SelectListItem
{
    public string Name { get; set; }

    public string Value { get; set; }
}

接下来让我们用 2 个方法定义一个简单的静态类。一种方法将创建 lambda 表达式,另一种方法将源 (IQueryable) 转换并选择为 IEnumerable:

 public static class QueryableExtensions
{
    public static IEnumerable<TItem> Select<TSource, TItem>(this IQueryable<TSource> source)
        where TSource : NameIdPair
        where TItem : SelectListItem, new()
    {
        if (source == null) throw new ArgumentNullException("source");

        return source.Select(CreateLambda<TSource, TItem>());
    }

    public static Expression<Func<TSource, TItem>> CreateLambda<TSource, TItem>()
        where TSource : NameIdPair
        where TItem : SelectListItem, new()
    {

        return (t) => new TItem { Name = t.Name, Value = t.Id };
    }
}

用法:

    //create an instance of an IQueryable<T> for demo purposes
var source = new[]
{
    new NameIdPair {Name = "test1_name", Id = "test1_Id"},
    new NameIdPair {Name = "test2_name", Id = "test2_Id"}
}.AsQueryable();

//you can call the "Select" extension method to select the queryable into an enum.
var enumerable = source.Select<NameIdPair, SelectListItem>();   
//'enumerable' is an IEnumerable<SelectListItem> instance

//or if you just want the lambda expression...
var lambda = QueryableExtensions.CreateLambda<NameIdPair, SelectListItem>();

//lambda.ToString() returns "t => new SelectListItem() {Name = t.Name, Value = t.Id}";

所以你去。不确定这是否是您正在寻找的,或者它是否符合您的需求。希望有人会发现它有用。

于 2015-10-31T00:16:32.833 回答