【问题标题】:Convert Func<T1,bool> to Func<T2,bool> in C#在 C# 中将 Func<T1,bool> 转换为 Func<T2,bool>
【发布时间】:2015-08-29 09:39:05
【问题描述】:

如何将Func&lt;DepartmentViewModel, bool&gt; 转换为 Func&lt;Department, bool&gt;?

我看过很多关于这个问题的帖子,但没有一个可以帮助我。

我调用这个函数:

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&lt;Department, bool&gt; 类型

这是我的对象:

class Department {
   public string name
}

class DepartmentViewModel{
   public string name
}

注意,我找到了最佳答案: Func&lt;DepartmentViewModel, bool&gt; some_function = whereCondition.Compile(); Func<Department, bool> converted = d => some_function( new DepartmentViewModel { Id=d.Id, Description=d.Descriptions } );

【问题讨论】:

  • 你能举一个具体的例子来说明你想要达到的目标吗?
  • 我想将“DTO where条件”从业务层传递到访问层public DepartmentViewModel GetSingle(System.Linq.Expressions.Expression&lt;Func&lt;DepartmentViewModel, bool&gt;&gt; whereCondition)public IEnumerable&lt; Department&gt; GetAll(Func&lt; Department, bool&gt; predicate = null)
  • 如何从Department 转换为DepartmentViewModel

标签: c# lambda expression


【解决方案1】:

您不能将Func&lt;T1,bool&gt; 更改为Func&lt;T2,bool&gt;,但您可以转换相同的表达式。

这需要一些工作,首先你必须传递Expression&lt;Func&lt;T,bool&gt;&gt;,然后你可以很容易地转换你的表达式来匹配传入的参数。

所以你可以改变你的方法,

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

【讨论】:

  • 什么是tc in line Expression body = tc.Visit(srcExp.Body);
  • @Farazjalili 在我看来,ec 的拼写错误。
  • @Farazjalili 只是错字
  • 注意,运行上面的代码后显示服务器错误页面并说没有为部门类型定义属性“Int32 Id”
  • @Farazjalili,DepartmentViewModel 是否拥有 Department 作为属性?阅读我的 cmets,代码应根据属性的声明方式进行更改。
【解决方案2】:

我假设您需要向实体框架(或其他一些查询提供程序)发出这些查询。在这种情况下,您需要使用表达式,而不仅仅是函数,因为只有前者存储需要由提供程序转换的查询信息(例如,转换为 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&lt;Department&gt;序列上,之后你可以应用你的过滤器:

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

【讨论】:

  • tnx for answer 你能否根据我的情况熟练地回答你的问题,这个函数与我的业务层相关 public DepartmentViewModel GetSingle(Expression> whereCondition) 我想通过 where whereCondition 到访问层具有像这样的签名 public IEnumerable GetAll(Func predicate = null) , DepartmentViewModel 和 Department 对象具有相似的属性
  • 不幸的是我没有直接访问 EF 提供程序我只能调用位于 DataAccessLayer 中的函数 public IEnumerable GetAll(Func predicate = null) 我只需要在哪里以及如何将 Func 转换为 Func
  • @Farazjalili:您能否将所有附加信息连贯地修改为原始问题?很难从 cmets 中了解您想要实现的目标。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-01
  • 2015-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-17
相关资源
最近更新 更多