在C#中将Func<T1,bool>转换为Func<T2,bool>

3

我该如何将Func<DepartmentViewModel, bool>转换为Func<Department, bool>

我已经查看了很多关于此问题的帖子,但都没有帮助到我。

我调用的是以下函数:

public DepartmentViewModel GetSingle(Expression<Func<DepartmentViewModel, bool>> whereCondition)

从 GUI 层面来看,代码如下:

_departmentService.GetSingle(de => de.Id ==id));

在我的业务层中,GetSingle函数内部,我必须调用

public IEnumerable<Department> GetAll(Func<Department, bool> predicate = null)

但是GetAll函数接受一个Func<Department, bool>类型参数

这是我的对象:

class Department {
   public string name
}

and

class DepartmentViewModel{
   public string name
}

关于这个问题,我找到了最佳答案:

Func<DepartmentViewModel, bool> some_function = whereCondition.Compile(); Func<Department, bool> converted = d => some_function( new DepartmentViewModel { Id=d.Id, Description=d.Descriptions } );

以上代码是将一个DepartmentViewModel类型的对象转换为Department类型的对象。其中whereCondition是一个用于筛选数据的条件。


4
你能给一个具体的例子来说明你想实现什么吗? - Douglas
我想将“DTO where条件”从业务层传递到访问层,以便将public DepartmentViewModel GetSingle(System.Linq.Expressions.Expression<Func<DepartmentViewModel, bool>> whereCondition)转换为public IEnumerable<Department> GetAll(Func<Department, bool> predicate = null) - Faraz jalili
你如何将 Department 转换为 DepartmentViewModel - Douglas
2个回答

1

您无法将 Func<T1,bool> 更改为 Func<T2,bool>,但可以转换相同的表达式。

这需要一些工作,首先您必须传递 Expression<Func<T,bool>>,然后您可以轻松地转换您的表达式以匹配传入的参数。

因此,您可以将您的方法更改为:

Expression<Func<DepartmentViewModel,bool>> srcLambda = 
     x => x.DepartmentName.StartsWith("Admin")

Expression<Func<Department,bool>> destLambda = 
     ConvertTo<Department,DepartmentViewModel>( srcLambda);

这里假设 DepartmentViewModel (DTO) 与 Department 拥有相同的字段。否则,您需要稍微修改代码以适应您的需求。
public static Expression<Func<TDest,bool>> 
      ConvertTo<TSrc,TDest>(Expression<Func<TSrc,bool>> srcExp)
{
    ParameterExpression destPE = Expression.Parameter(typeof(TDest));

    ExpressionConverter ec = new ExpressionConverter(typeof(TSrc),destPE);
    Expression body = ec.Visit(srcExp.Body);
    return Expression.Lambda<Func<TDest,bool>>(body,destPE);
} 

public class ExpressionConverter: ExpressionVisitor{

    private Type srcType;
    private ParameterExpression destParameter;

    public ExpressionConverter(Type src, ParameterExpression dest){
        this.srcType = src;
        this.destParameter= dest;
    } 

    protected override Expression 
       VisitParameter(ParameterExpression node)
    {
        if(node.Type == srcType)
            return this.destParameter;
        return base.VisitParameter(node);
    }
}

在代码行Expression body = tc.Visit(srcExp.Body);中,tc是什么? - Faraz jalili
@Farazjalili 对我来说,这只是一个打字错误,应该是 ec - user743382
@Farazjalili 这只是个打字错误。 - Akash Kava
运行以上代码后,显示服务器错误页面并提示“Department”类型未定义“Int32 Id”属性,这太神奇了。 - Faraz jalili
@Farazjalili,DepartmentViewModel有Department属性吗?请阅读我的评论,代码应该根据属性的声明方式进行更改。 - Akash Kava

0

我猜你需要向Entity Framework(或其他查询提供程序)发出这些查询。在这种情况下,您需要使用表达式而不仅仅是函数,因为只有前者存储了查询信息,这些信息需要由提供程序进行转换(例如转换为SQL查询)。

这里是一个简单的例子:

Expression<Func<DepartmentViewModel, bool>> filterDVM = dvm => dvm.Name == "abc";

首先,您需要编写一些逻辑来接受一个Department并将其转换为DepartmentViewModel

Expression<Func<Department, DepartmentViewModel>> getViewModel = dep => 
    new DepartmentViewModel
    {
        Name = dep.Name,
        Location = dep.Location,
    };

一旦你拥有了这个,你就可以将你的转换应用到 IQueryable<Department> 序列上,之后你可以应用你的过滤器:

var dvm = context.Departments.Select(getViewModel).Where(filterDVM);

谢谢您的回答。您可否根据我的情况调整一下您的回答?这个函数与我的业务层有关,它是这样的公共函数:DepartmentViewModel GetSingle(Expression<Func<DepartmentViewModel, bool>> whereCondition) 。我想将 whereCondition 参数传递到访问层,而该层具有以下签名:public IEnumerable< Department> GetAll(Func< Department, bool> predicate = null)。DepartmentViewModel 和 Department 对象具有相似的属性。 - Faraz jalili
不幸的是,我没有直接访问 EF 提供程序的权限,我只能调用位于 DataAccessLayer 中的 public IEnumerable<Department> GetAll(Func<Department, bool> predicate = null) 函数。我只需要知道在哪里以及如何将 Func<DepartmentsViewmodel,bool> 转换为 Func<Departments,bool>。 - Faraz jalili
@Farazjalili:你能把所有的额外信息重新整合到你原来的问题中吗?从评论中很难读出你想要实现什么。 - Douglas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接