【问题标题】:can not convert type func<T,bool> to bool无法将类型 func<T,bool> 转换为 bool
【发布时间】:2018-10-15 07:27:48
【问题描述】:

我有以下 linq,我想将不同的条件传递给 where 子句,但出现错误:

 var rslt = (from t in cr.faultStatAlt
                   join v in cr.errorCatGroup
                   on t.m_error_id equals v.m_error_id
                   join h in cr.masterAlarm on t.m_inv_error_details equals h.pc_group_pattern into ps
                   from h in ps.DefaultIfEmpty()
                   join s in cr.MasterDataTurbine on t.m_turbine_id equals s.m_turbine_id
                   where (whereClause)
                   group t.error_duration by v.m_error_subgroup_name into k
                   select new faulttest
                   {
                       m_error_subgroup = k.Key,
                       error_duration = Math.Round(k.Sum() / 3600, 2)


                   }).ToString();

我想让它动态的条件是:

 Func<t_fault_stat_alt, bool> whereClause = t => t.m_date >= dt1 && t.m_date <= dt2 && t.m_grid_loss==true;

【问题讨论】:

  • 我怀疑您必须将部分/全部从查询语法转换为方法语法。
  • @Fildor - 错误列在问题的标题中。
  • @just.another.programmer 哈哈,对了...我去喝杯咖啡...
  • 你在调用你的 Func 吗?试试whereClause.Invoke(parameter) 或者干脆whereClause(parameter)
  • 您可以简单地以 Query 格式的 Where 子句传递 Func 布尔逻辑,类似于 where t.m_date &gt;= dt1 &amp;&amp; t.m_date &lt;= dt2 &amp;&amp; t.m_grid_loss==true。这会方便得多,因为您不是在运行时构造 Func

标签: c# linq


【解决方案1】:

您不能在查询语法中将 lambda 传递给 where - 您需要改用方法语法。类似的东西

   var fltr = (from t in cr.faultStatAlt
               join v in cr.errorCatGroup
               on t.m_error_id equals v.m_error_id
               join h in cr.masterAlarm on t.m_inv_error_details equals h.pc_group_pattern into ps
               from h in ps.DefaultIfEmpty()
               join s in cr.MasterDataTurbine on t.m_turbine_id equals s.m_turbine_id)
              .Where (whereClause);

   var rslt = (from t in fltr
               group t.error_duration by v.m_error_subgroup_name into k
               select new faulttest
               {
                   m_error_subgroup = k.Key,
                   error_duration = Math.Round(k.Sum() / 3600, 2)


               }).ToString();

解释-

查询语法只是编译器为您提供的一种快捷方式。整个查询在编译时使用 LINQ 方法调用重写。对于 where 子句,编译器需要一个计算结果为 bool 的语句 - 编译器将该语句转换为 lambda。

您给编译器一个 lambda 以 (Func&lt;t_fault_stat_alt, bool&gt;) 开头 - 它不知道如何将其转换为 bool

【讨论】:

  • 您当然可以在查询语法中使用它,您只需使用正确的参数调用它:where whereclause(t)
  • 您可能需要注意我添加的答案,以警告人们在不合适时使用它(例如,使用 EntityFramework)。
  • 哦...另外,您可以将Func&lt;T, bool&gt; 传递到 LINQ 中...但您需要实际调用它才能使其工作from t in ... where whereClause(t) ...
  • @pinkfloydx33 两者之间有一个关键区别 - 使用where whereclause(t),编译器将编写一个 MethodCallExpression 来调用带有 ParameterExpression t 的whereclause(t)。使用.Where(whereclause),您只得到谓词。 这很关键 b/c 许多查询提供程序(如 LINQ to SQL 和 LINQ to EF)不支持 MethodCallExpression。
  • @X39 只有在向查询语法中添加方法调用时才会出现这个问题。
【解决方案2】:

即使问题已经被标记为正确,我也需要注意一些可能在 cmets 中丢失的重要内容。

如果您使用实体框架(或接受Expression 而不是Func 的其他任何东西),则需要使用不同的类型。

鉴于以下代码,其中 Tag 是包含 int 字段 Id(+ 其对应列)的随机对象,而 cntxt 是实体框架 DBContext,您将产生以下两个 SQL 查询:

Func<Data.Net.Tag, bool> cond = (tag) => tag.Id == 1;
var query = cntxt.Tags.Where(cond);
query.ToArray();
// SELECT "Extent1"."Id", "Extent1"."Name" FROM "public"."Tags" AS "Extent1"

query = cntxt.Tags.Where((tag) => tag.Id == 1);
query.ToArray();
// SELECT "Extent1"."Id", "Extent1"."Name" FROM "public"."Tags" AS "Extent1" WHERE 1 = "Extent1"."Id"

原因是 Entity Framework 使用 IQueryable 来实际构建这些 SQL 查询。

由于IQueryable 也实现了IEnumerable,但您可能会因为外观而陷入期望FuncExpression 具有相同行为的陷阱。如果实际检查方法本身,则差异会更加明显:

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

要仍然获得相同的行为(过滤器方法),您必须将方法头更改为如下内容:

void MyWhere<T>(..., Expression<Func<T, bool>> cond)

有关此的更多信息,请查看例如: Why would you use Expression<Func<T>> rather than Func<T>? 或谷歌C# Expression :)

【讨论】:

  • 我会很惊讶,如果你能提供一个Func,其中应该是Expression,这应该是一个编译错误。没有理由用 Func 替换 Expression,只是两者使用 Lambda 进行简单查询的语法相似,但它们的工作方式完全不同
  • 那一刻,有些东西实现了IQueryable,你可能会遇到两种都被接受的情况(例如public static IQueryable&lt;TSource&gt; Where&lt;TSource&gt;(this IQueryable&lt;TSource&gt; source, Expression&lt;Func&lt;TSource, bool&gt;&gt; predicate) vs public static IEnumerable&lt;TSource&gt; Where&lt;TSource&gt;(this IEnumerable&lt;TSource&gt; source, Func&lt;TSource, bool&gt; predicate);)。
  • 虽然......你是对的,因为我的推理几乎是废话......会解决这个问题(要把那个放在早上咖啡不足的问题上)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多