表达式<func <tsource,tresult =“”>&gt;带参数的选择器

时间:2016-10-11 09:10:58

标签: c# .net entity-framework linq

我正在尝试创建一个LINQ表达式选择器来容纳另一个IQueryable作为参数。 dot.net小提琴是here

我正在尝试对 CustomSelector 进行编码以接受IQueryable parameter并根据具体情况将其应用于选择器。

另外,我想在 CustomSelector 的调用中包含要应用于IQueryable参数的每行的值。

这样我就不必编写2个自定义选择器了。

替代方案是 GetMyData2 功能。

测试代码如下:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

public class Entity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class EntityDto
{
    public int Id { get; set; }
    public string Name { get; set; }    
    public int Count { get; set; }
}

public class TestController 
{
    public List<Entity> entityList { get; set; }


    public List<EntityDto> GetMyData(string condition)
    {
        List<Entity> sourceEntityList = new List<Entity>();
        List<EntityDto> returnEntityList = new List<EntityDto>();

        switch(condition)
        {
            case "A":       
            returnEntityList = sourceEntityList.Where(x=>x.Name == "A").Select(y=>CustomSelector(sourceEntityList.Where(z=>z.Name=x.Name)));
        return returnEntityList;
            break;
        case "B":       
        default:
            returnEntityList = sourceEntityList.Where(x=>x.Name == "B").Select(y=>CustomSelector(sourceEntityList.Where(z=>z.Name != x.Name)));
        return returnEntityList;
            break;
        }

    }

    public List<EntityDto> GetMyData2(string condition)
    {
        List<Entity> sourceEntityList = new List<Entity>();
        List<EntityDto> returnEntityList = new List<EntityDto>();

        switch(condition)
        {
            case "A":       
            returnEntityList = sourceEntityList.Where(x=>x.Name == "A").Select(ent=>
                                                                               new EntityDto()
                {
                    Id = ent.Id
                    ,
                    Name = ent.Name                                       
                    ,
                    Count =  sourceEntityList.Count(z=>z.Name== ent.Name)
                }
                                                                              ).ToList();
        return returnEntityList;
            break;
        case "B":       
        default:
            returnEntityList = sourceEntityList.Where(x=>x.Name == "B").Select(ent=>
                                                                               new EntityDto()
                {
                    Id = ent.Id
                    ,
                    Name = ent.Name                                       
                    ,
                    Count =  sourceEntityList.Count(z=>z.Name != ent.Name)
                }
                                                                              ).ToList();
        return returnEntityList;
            break;
        }

    }

    protected Func<Entity, EntityDto> CustomSelector(IQueryable<Entity> paramQuery)
        {

                return ent => new EntityDto()
                {
                    Id = ent.Id
                    ,
                    Name = ent.Name                                       
                    ,
                    Count =  paramQuery.Count()
                };

        }
}

1 个答案:

答案 0 :(得分:1)

你在问什么是不可能没有一些表达式树操作。

您可以使用某些第三方软件包,例如LinqKitAsExpandable / Invoke)或AutoMapper,但这是基于表达式原型和简单参数替换程序的自定义解决方案

参数替换器:

public static class ExpressionUtils
{
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
    {
        return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
    }

    class ParameterReplacer : ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == Source ? Target : base.VisitParameter(node);
        }
    }
}

CustomSelector:

protected Expression<Func<Entity, EntityDto>> CustomSelector(Expression<Func<Entity, IQueryable<Entity>>> paramQuery)
{
    Expression<Func<Entity, IQueryable<Entity>, EntityDto>> prototype = (e, q) => new EntityDto
    {
        Id = e.Id,
        Name = e.Name,
        Count = q.Count(),
    };
    return Expression.Lambda<Func<Entity, EntityDto>>(
        prototype.Body
            .ReplaceParameter(prototype.Parameters[0], paramQuery.Parameters[0])
            .ReplaceParameter(prototype.Parameters[1], paramQuery.Body),
        paramQuery.Parameters[0]);
}

用法:

public List<EntityDto> GetMyData(string condition)
{
    var sourceEntityList = new List<Entity>().AsQueryable();
    switch (condition)
    {
        case "A":
            return sourceEntityList.Where(x => x.Name == "A")
                .Select(CustomSelector(x => sourceEntityList.Where(y => y.Name == x.Name))).ToList();
        case "B":
        default:
            return sourceEntityList.Where(x => x.Name == "B")
                .Select(CustomSelector(x => sourceEntityList.Where(y => y.Name != x.Name))).ToList();
    }
}