您会将LINQ查询抽象为扩展方法吗

您会将LINQ查询抽象为扩展方法吗,linq,extension-methods,abstraction,maintainability,cyclomatic-complexity,Linq,Extension Methods,Abstraction,Maintainability,Cyclomatic Complexity,在我当前的项目中,我们为代码度量“可维护性指数”和“循环复杂度”设定了一些目标。维修性指数应为60或更高,拟周期复杂度应为25或更低。我们知道60及以上的可维护性指数是相当高的 我们还使用大量linq来过滤/分组/选择实体。我发现这些linq查询在可维护性指数上的得分并没有那么高。 将这些查询抽象为扩展方法会给我一个更高的可维护性索引,这很好。但是在大多数情况下,扩展方法不再是泛型的,因为我将它们用于我的类型,而不是泛型类型 例如,以下linq查询与扩展方法: Linq查询 List.Where

在我当前的项目中,我们为代码度量“可维护性指数”和“循环复杂度”设定了一些目标。维修性指数应为60或更高,拟周期复杂度应为25或更低。我们知道60及以上的可维护性指数是相当高的

我们还使用大量linq来过滤/分组/选择实体。我发现这些linq查询在可维护性指数上的得分并没有那么高。 将这些查询抽象为扩展方法会给我一个更高的可维护性索引,这很好。但是在大多数情况下,扩展方法不再是泛型的,因为我将它们用于我的类型,而不是泛型类型

例如,以下linq查询与扩展方法:

Linq查询

List.Where(m => m.BeginTime >= selectionFrom && m.EndTime <= selectionTo)

List.Where(m=>m.BeginTime>=selectionFrom&&m.EndTime m.BeginTime>=selectionFrom&&m.EndTime我给你的建议是……不要成为你的指标的奴隶!它们是机器生成的,只用于指导。它们永远不会取代有经验的程序员


您认为哪一个适合您的应用程序?

您不应该为了度量而添加类。任何度量都是为了使您的代码更好,但盲目遵循规则,即使是最好的规则,实际上也可能损害您的代码

我认为坚持某些可维护性和复杂性指标不是一个好主意。我相信它们对于评估旧代码非常有用,也就是说,当您继承了一个项目并需要评估其复杂性时。但是,提取一个方法是荒谬的,因为您没有获得足够的分数

只有在重构为代码增加价值的情况下才进行重构。这种价值是一个复杂的人类衡量标准,无法用数字来表达,估计它正是编程经验在优化、可读性、干净API、酷代码、简单代码、快速发布、泛化和特定代码之间找到平衡的关键所在腐败等

这是你应该遵循的唯一标准,但它并不总是每个人都同意的标准

对于您的示例,如果反复使用相同的LINQ查询,那么在
Extensions
文件夹中创建一个
EnumerableExtensions
并将其解压缩是非常有意义的。但是,如果使用一次或两次,或者需要更改,详细查询会更好

我也不明白为什么你说它们不是通用的,有点负面的含义。你不需要到处都是泛型。事实上,当编写扩展方法时,你应该考虑你可以选择的最具体的类型,以免污染其他类的方法集。如果你想让你的助手只使用<代码> iQueaby,re完全可以为

这个IEnumerable
声明一个扩展方法。顺便说一句,在您的示例中有多余的强制转换。。摆脱它


不要忘记,工具是愚蠢的。我们人类也是如此。
不:在这种情况下,我会忽略圈复杂度——你原来拥有的更好

问问自己,什么更具解释性。这是:

List.Where(m => m.BeginTime >= selectionFrom && m.EndTime <= selectionTo)
第一种方法清楚地表达了您想要什么,而第二种方法则没有。了解“FilterBy”的含义的唯一方法是深入源代码并查看其实现


将查询片段抽象为扩展方法在更复杂的场景中是有意义的,在这些场景中,很难一目了然地判断查询片段在做什么。

我个人同意扩展方法策略。我在少数实际应用程序中毫无问题地使用了它

对我来说,这不仅关乎指标,还关乎代码的可重用性。请参见以下psuedo示例:

var x = _repository.Customers().WhichAreGoldCustomers();

var y = _repository.Customers().WhichAreBehindInPayments();
拥有这两种扩展方法可以实现您的度量目标,而且它还为“黄金客户的定义提供了一个位置”。当不同的开发人员需要与“黄金客户”合作时,他们不会在不同的位置创建不同的查询

此外,它们是可组合的:

var z = _repository.Customers().WhichAreGoldCustomers().WhichAreBehindInPayments();
我认为这是一个成功的方法


我们面临的唯一问题是,存在一个ReSharper错误,有时扩展方法的Intellisense会变得疯狂。您键入“.Whic”,它会让您选择所需的扩展方法,但当您“tab”在它上面,它在代码中加入了一些完全不同的东西,而不是您选择的扩展方法。我已经考虑过为此从ReSharper切换,但是…不:)

我在一些地方使用过这种技术,例如,类支付具有相应的类PaymentLinqExtensions,该类为支付提供特定于域的扩展

在您给出的示例中,我将选择一个更具描述性的方法名称。还有一个问题是这个范围是包含的还是独占的,否则看起来就可以了

如果你的系统中有多个对象,其中有一个日期的概念是常见的,那么考虑一个接口,可能是IHaveADate(或者更好的东西:)/P>


也许我的问题让我们看起来像是被指标所奴役,但事实并非如此。我们使用它作为指导,但也为自己设定了很高的目标,以确保每个人都考虑如何使您的方法尽可能干净和可维护。我对使用什么有一些想法,但想看看其他人对它的看法。度量仅仅是一种度量,而不是一个目标。我对任何无法解释的黑匣子的可维护性指数都有点怀疑。至少在圈复杂度下,可以确定实际测量的内容。你知道除了(没有)解释之外,是否还有其他解释?我同意你的立场;需要注意的是,根据问题,这一变化明显改善了可维护性指数rat
var x = _repository.Customers().WhichAreGoldCustomers();

var y = _repository.Customers().WhichAreBehindInPayments();
var z = _repository.Customers().WhichAreGoldCustomers().WhichAreBehindInPayments();
public static IQueryable<T> WithinDateRange(this IQueryable<T> source, DateTime from, DateTime to) where T:IHaveADate
public static IQueryable<T> WithinDateRange(this IQueryable<T> source, DateRange range) where T:IHaveADate
public static IEnumerable<T> WithinDateRange(this IEnumerable<T> source, DateRange range, Func<DateTime,T> getDate)
var filtered = myThingCollection.WithinDateRange(myDateRange, x => x.Date)