哪些实践可以防止以IEnumerable 作为参数的意外延迟执行? [关闭]

问题描述 投票:6回答:3

存在一些与此类似的问题,涉及正确的输入和输出类型like this。我的问题是,哪些良好的实践,方法命名,选择参数类型或类似方法可以防止延后的执行事故?

这些在IEnumerable中最普遍,这是一种非常常见的参数类型,因为:

但是,它也引入了延迟执行。现在,当我们认为最好的想法是采用最基本的类型时,我们在设计方法(尤其是扩展方法)时可能出错了。所以我们的方法看起来像:

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> lstObject)
{
    foreach (T t in lstObject)
       //some fisher-yates may be
}

危险显然是当我们将以上函数与惰性Linq及其如此敏感。混合使用时>

var query = foos.Select(p => p).Where(p => p).OrderBy(p => p); //doesn't execute
//but
var query = foos.Select(p => p).Where(p => p).Shuffle().OrderBy(p => p);
//the second line executes up to a point.

更大的编辑:

重新打开:对语言功能的批评不是建设性的-但是,寻求良好实践是StackOverflow的亮点。更新了问题以反映这一点。

这里有个大修改:

为了澄清以上内容-我的问题不是关于第二个表达式没有得到评估,严重的是。程序员知道这一点。我担心的是Shuffle方法实际上直到那时才执行查询。请参阅第一个查询,其中什么都不会执行。现在类似地,当构造另一个Linq表达式(应稍后执行)时,我们的自定义函数正在播放spoilsport。换句话说,如何让调用者知道Shuffle不是他们在Linq表达式那一刻想要的函数。我希望这一点可以解决。道歉! :)尽管它就像检查方法一样简单,但我想问的是你们通常如何进行防御性编程。]

上面的示例可能没有那么危险,但是您明白了。可以肯定的是,(自定义)函数不能与Linq延迟执行的想法配合使用。问题不仅与性能有关,而且还与意外的副作用有关。

但是像这样的函数在Linq上可以正常工作:

public static IEnumerable<S> DistinctBy<S, T>(this IEnumerable<S> source, 
                                              Func<S, T> keySelector)
{
    HashSet<T> seenKeys = new HashSet<T>(); //credits Jon Skeet
    foreach (var element in source)
        if (seenKeys.Add(keySelector(element)))
            yield return element;
}

您可以看到两个函数都使用IEnumerable<>,但是调用者不知道这些函数如何反应。那么你们在这里采取的一般警告措施是什么?

  1. 适当地命名我们的自定义方法,以便它使调用者知道Linq的预示是否正确。

  2. lazy

  3. 方法移动到另一个名称空间,并将Linq -ish保留到另一个名称空间,以便至少给出某种想法?
  4. 不接受IEnumerable作为执行immediately的方法的参数,而是采用更多派生的类型或具体的类型本身,从而使IEnumerable单独用于惰性方法吗?这给调用者增加了执行可能未执行的表达式的负担?这对于我们来说是完全可能的,因为在Linq世界之外,我们几乎不处理IEnumerable,并且大多数基本集合类至少实现了ICollection

  5. 还是其他?我特别喜欢第3个选项,这就是我要使用的选项,但我想先获得您的想法。我已经从甚至接受Linq并在方法内部对其执行IEnumerable或类似操作的优秀程序员那里看到了很多代码(很少有ToList()这样的扩展方法!)。我不知道他们如何应对副作用。

Edit:

在投票和回答之后,我想澄清一下,这并不是关于程序员不了解Linq的工作方式(我们的熟练程度可能是某种程度,但这是另一回事),但是当时编写的许多函数都没有考虑Linq。现在,将立即执行的方法与Linq扩展方法链接在一起会使其变得危险。所以我的问题是,程序员会遵循一般的准则来让调用者从Linq方面知道要使用什么,而不要做什么? [更多的是关于防御性编程,而不是如果您不知道要使用它然后我们就帮不上忙!(或至少我相信)。

存在一些与此类似的问题,涉及诸如此类的正确输入和输出类型。我的问题是,什么好的做法,方法命名,选择参数类型或类似方法可以维护...

c# linq parameters ienumerable design-principles
3个回答
7
投票

您可以看到两个函数都使用IEnumerable<>,但调用者不知道这些函数如何反应。


1
投票

使用IEnumerable


0
投票

延迟执行与类型无关。如果以这种方式编写代码,则任何使用迭代器的linq方法都有可能推迟执行。 IListSelect()Where()例如所有人都使用迭代器,因此推迟执行。是的,那些方法期望使用OrderByDescending(),但这并不意味着IEnumerable<T>是问题。

© www.soinside.com 2019 - 2024. All rights reserved.