加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 确保延迟执行只执行一次

发布时间:2020-12-15 06:47:11 所属栏目:百科 来源:网络整理
导读:我遇到了一个奇怪的问题,我想知道我应该做什么. 我有这个类返回一个IEnumerable MyClass这是延期执行.现在有两个可能的消费者.其中一个排序结果. 请参见以下示例: public class SomeClass{ public IEnumerableMyClass GetMyStuff(Param givenParam) { doubl
我遇到了一个奇怪的问题,我想知道我应该做什么.

我有这个类返回一个IEnumerable< MyClass>这是延期执行.现在有两个可能的消费者.其中一个排序结果.

请参见以下示例:

public class SomeClass
{
    public IEnumerable<MyClass> GetMyStuff(Param givenParam)
    {
        double culmulativeSum = 0;
        return myStuff.Where(...)
                      .OrderBy(...)
                      .TakeWhile( o => 
                      {
                          bool returnValue = culmulativeSum  < givenParam.Maximum;
                          culmulativeSum += o.SomeNumericValue;
                          return returnValue; 
                      };
    }
}

消费者称延迟执行只有一次,但是如果它们被称为更多的结果,结果将是错误的,因为culmulativeSum不会被重置.我通过无意识的单元测试发现了这个问题.

解决这个问题的最简单的方法是添加.ToArray(),并以一点点开销为代价去除延迟执行.

我也可以在消费者阶层添加单元测试,以确保他们只将它们称为一次,但这并不会阻止任何新的消费者在未来从这个潜在的问题编码.

我想到的另一件事是让后续执行.
就像是

return myStuff.Where(...)
       .OrderBy(...)
       .TakeWhile(...)
       .ThrowIfExecutedMoreThan(1);

显然这不存在.
实施这样的事情会是个好主意,你会怎么做?

否则,如果有一个大的粉红色的大象,我看不到,指出它将不胜感激. (我觉得有一个,因为这个问题是一个非常基本的情况:|)

编辑:

这是一个不好的消费者使用示例:

public class ConsumerClass
{
    public void WhatEverMethod()
    {
        SomeClass some = new SomeClass();
        var stuffs = some.GetMyStuff(param);
        var nb = stuffs.Count(); //first deferred execution
        var firstOne = stuff.First(); //second deferred execution with the culmulativeSum not reset
    }
}

解决方法

您可以通过简单地将您的方法转换为 iterator来解决不正确的结果问题:
double culmulativeSum = 0;
var query = myStuff.Where(...)
       .OrderBy(...)
       .TakeWhile(...);
foreach (var item in query) yield return item;

它可以以简单的扩展方法封装:

public static class Iterators
{
    public static IEnumerable<T> Lazy<T>(Func<IEnumerable<T>> source)
    {
        foreach (var item in source())
            yield return item;
    }
}

那么在这种情况下你需要做的就是用Iterators.Lazy调用包围原始方法体.例如:

return Iterators.Lazy(() =>
{
    double culmulativeSum = 0;
    return myStuff.Where(...)
           .OrderBy(...)
           .TakeWhile(...);
});

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读