Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 迭代器块的正确使用_C#_.net_Iterator - Fatal编程技术网

C# 迭代器块的正确使用

C# 迭代器块的正确使用,c#,.net,iterator,C#,.net,Iterator,我之前在重构一些代码时,遇到了一个迭代器块的实现,我对此不太确定。在客户机为某些数据调用外部API的系统的集成层中,我有一组转换器,这些转换器将从API返回的数据转换为逻辑层中使用的业务实体集合。常见的translator类如下所示: // translate a collection of entities coming back from an extrernal source into business entities public static IEnumerable<MyBus

我之前在重构一些代码时,遇到了一个迭代器块的实现,我对此不太确定。在客户机为某些数据调用外部API的系统的集成层中,我有一组转换器,这些转换器将从API返回的数据转换为逻辑层中使用的业务实体集合。常见的translator类如下所示:

// translate a collection of entities coming back from an extrernal source into business entities
public static IEnumerable<MyBusinessEnt> Translate(IEnumerable<My3rdPartyEnt> ents) {

    // for each 3rd party ent, create business ent and return collection
    return from ent in ents
           select new MyBusinessEnt {
               Id = ent.Id,
               Code = ent.Code
           };
}
//将从外部源返回的实体集合转换为业务实体
公共静态IEnumerable Translate(IEnumerable ents){
//对于每个第三方ent,创建业务ent和退货托收
从耳鼻喉科返回耳鼻喉科
选择新的MyBusinessEnt{
Id=ent.Id,
代码=ent.Code
};
}
今天我遇到了以下代码。同样,它是一个translator类,其目的是将参数中的集合转换为方法返回类型。但是,这次它是一个迭代器块:

// same implementation of a translator but as an iterator block
public static IEnumerable<MyBusinessEnt> Translate(IEnumerable<My3rdPartyEnt> ents) {
    foreach(var ent in ents)
    {
        yield return new MyBusinessEnt {
            Id = ent.Id,
            Code = ent.Code
        };
    }
}
//与转换器的实现相同,但作为迭代器块
公共静态IEnumerable Translate(IEnumerable ents){
foreach(在ents中的变量)
{
收益回报新业务{
Id=ent.Id,
代码=ent.Code
};
}
}

我的问题是:这是迭代器块的有效使用吗?我看不出以这种方式创建translator类的好处。这会导致一些意外行为吗?

是的,这是有效的。foreach的
foreach
具有可调试的优点,因此我倾向于采用这种设计。

第一个示例不是迭代器。它只是创建并返回一个
IEnumerable


第二个是迭代器,我看不出有什么问题。每次调用方迭代该方法的返回值时,
yield
将返回一个新元素。

当每个代码运行时,主要差异将启用第一个被延迟,直到返回值被迭代,而第二个立即运行。我的意思是for循环正在强制运行迭代。类公开了一个
IEnumerable
,在本例中是延迟的,这是另一回事

这与简单的
Select
相比没有任何好处<代码>收益率的真正力量是当涉及到一个条件时:

foreach(var ent in ents)
{
    if(someCondition)
    yield return new MyBusinessEnt {
        Id = ent.Id,
        Code = ent.Code
    };
}

是的,效果很好,结果非常相似

两者都创建一个能够返回结果的对象。两者都依赖于源可枚举项保持不变,直到结果完成(或缩短)。两者都使用延迟执行,即在迭代结果时一次创建一个对象


不同之处在于,第一个示例返回一个使用库方法生成枚举数的表达式,而第二个示例创建一个自定义枚举数。

您的两个示例执行的操作几乎完全相同。查询版本将被重写为Select调用,Select编写方式与第二个示例完全相同;它迭代源集合中的每个元素,并返回一个转换后的元素


这是迭代器块的一种完全有效的用法,尽管当然不再需要像这样编写自己的迭代器块,因为您可以只使用
Select

对我来说似乎完全有效-它提供了两个实体之间的编译安全转换。它有什么问题?因此迭代器块可能会给任何试图在系统中稍后调试foreach的人带来一些混乱?我不认为一定会有任何混乱;
foreach
块可以更轻松地定位正在翻译的行项目。如果翻译变得非常琐碎,这允许进行更简单的调试。不过,这两种方法都是完美的find实现。请稍等——与简单的Where后跟Select相比,您的版本没有任何好处。是的,Chris Shouts的评论是正确的;两者都推迟执行。@EricLippert是的,因为他使用的是循环而不是选择。但正如我所说,在这种情况下,我只会使用普通Linq。你确定吗?我认为两者都是按需有效地创建了它们的值-即第二个值不会立即运行。@Aliostad:第一个值会立即返回一个对象,该对象会延迟其执行,直到调用MoveNext为止。第二个返回一个对象,该对象将延迟其执行,直到调用MoveNext。它们都使用延迟执行。但是是的,有“两个跃点”可以从第一个跃点中获取数据,而在第二个跃点中只有“一个跃点”。性能差异可能很小。@Aliostad:我假设下一票是“第二个立即运行”。该语句很容易解释为第二个没有延迟执行。好的,但在本例中不需要创建自定义迭代器,对吗?正如@Aliostad指出的,迭代器块最好与条件语句一起使用。因此,第二种方法的可读性\可调试性可能稍差,因此第一种方法可能更适合这种情况。另外,区别在于,自定义枚举器立即运行,而第一种方法(
从该方法中选择此方法)运行延迟。@Aliostad-我不太明白。。。因此,第一个示例返回一个尚未枚举的集合。第二个是每次调用时枚举返回集合?“是这样吗?”詹姆斯刘易斯:林克处理条件句很好。这就是
的作用。
的作用。@jameslewis:The
yield return
基本上暂停方法中的代码并返回项目,然后当您请求下一个项目时,代码将从该点开始循环,直到再次到达
yield return
。因此,代码不会在每次需要时都枚举源代码