编写可在任何 IEnumerable(包括 IQueryable)上调用的泛型扩展方法的正确方法是什么?

What's the correct way to write a generic extension method that can be called on any IEnumerable (including an IQueryable)?

提问人:Joseph Morgan 提问时间:10/28/2023 更新时间:10/28/2023 访问量:63

问:

我有一些静态函数,它们封装了我们执行的常见数据库操作。

例:

public static IQueryable<Round> FilterByStandardExclusionCriteria(
  this IQueryable<Round> rounds,
  bool someExclusionFlag = true,
  bool otherExclusionFlag = true,
)
{
  return (
    from round in rounds
    where (
      // Filter down the list of rounds based on exclusion flags
    )
    select round
  );
}

这通常工作得很好,但有时 LINQ 到 SQL 的转换会失败,我们必须在调用某些函数之前显式启用对 LINQ 查询的客户端计算。

我将扩展方法重写为泛型,最终看起来像这样:

public static T FilterByStandardExclusionCriteria<T>(
  this T rounds,
  bool someExclusionFlag = true,
  bool otherExclusionFlag = true,
) where T : IEnumerable<Round>
{
  return (
    from round in rounds
    where (
      // Filter down the list of rounds based on exclusion flags
    )
    select round
  );
}

但是这样做会给我一个编译器错误,说

无法将类型“System.Collections.Generic.IEnumerable<Namespace.Round>”隐式转换为“T”。

我试图用 显式将返回值转换为 T,但这样做会导致在运行时抛出以下异常:(T)return ...

引发异常:“System.Private.CoreLib.dll 中的”System.InvalidCastException“:”无法将类型为'WhereEnumerableIterator'1[Namespace.Round]'的对象强制转换为类型'Microsoft.EntityFrameworkCore.DbSet'1[Namespace.Round]'。

编写可在任何 IEnumerable 上调用的泛型扩展方法的正确方法是什么?

C# asp.net LINQ 泛型

评论

0赞 Dai 10/28/2023
使用 ,而不是 ,并确保使用 而不是 raw 。IQueryable<T>IEnumerable<T>Expression<Func<>>Func<>
3赞 Charlieface 10/29/2023
“有时 LINQ 到 SQL 的转换会失败,我们必须显式启用对 LINQ 查询的客户端计算”听起来是个坏主意。您可能应该先尝试解决翻译问题。
0赞 Joseph Morgan 10/31/2023
@Charlieface完全同意你的观点,但有时解决方案启用对查询的显式客户端评估,对吧?如果转换在复杂查询上失败,并且我确定转换失败的原因是查询的一部分涉及具有不可翻译业务逻辑的表达式,那么构建查询以使业务逻辑尽可能晚地发生,然后在运行该部分之前切换到客户端评估,这难道不是正确的操作过程吗?
0赞 Joseph Morgan 10/31/2023
@Dai 你在哪里看到用法?你能再说下去吗?我在相关代码中使用了 Func 类型的参数<>我的错误与此相关吗?Func<>
0赞 Charlieface 10/31/2023
不一定,有时解决方案是重新考虑业务逻辑,以便可以在服务器端完成。我对此表示怀疑:大多数情况下,当有人决定将逻辑重构为函数时,就会发生这种情况,这不适用于 EF 翻译等。是的,如果不可能,那么唯一的选择是客户端评估

答:

0赞 pakeha_by 10/28/2023 #1

您可以保持原样(使用 IQueryable 类型)并按如下方式调用它:FilterByStandardExclusionCriteria

enumerableCollection.AsQueryable().FilterByStandardExclusionCriteria()

评论

0赞 Joseph Morgan 10/28/2023
哦,哇,刚刚调查了一下。似乎正是我需要的。总的来说,我很好奇为什么泛型方法不起作用。如果查询语句返回与输入相同的类型,而输入保证与返回类型相同,为什么还需要强制转换返回结果?
0赞 pakeha_by 10/28/2023
如果您将其声明为public static IEnumerable<T> FilterByStandardExclusionCriteria<T>( this IEnumerable<T> rounds...