使用反射创建 lambda 表达式,例如 x => new { .. }



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

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

我怎么做,或者我在哪里可以找到构造这种表达式树的引用。

谢谢

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

在你的例子中,它看起来像这样:

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

在运行时知道什么类型信息(如果有的话)有点不清楚。借用Nicholas Butler的答案(因为它被接受了)让我们假设你将"知道"源类型(即IQueryable源中T的类型是什么),并且你将"知道"目标类型(从IQueryable返回的项类型)。选择扩展方法)。当我说"知道"时,我的意思是它是可以在运行时发现的东西,不需要动态、反射、延迟绑定等。否则,他的解决方案只会在源和目标类型恰好具有那些匹配名称的属性(即。"名称/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; }
}

接下来,让我们定义一个简单的静态类,它有两个方法。一个方法将创建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}";

就是这样。不确定这是否是你想要的,或者它是否符合你的需求。

相关内容

  • 没有找到相关文章

最新更新