C# 将IEnumerable与一个项目一起使用时,有什么更好的方法:收益回报或回报[]?

C# 将IEnumerable与一个项目一起使用时,有什么更好的方法:收益回报或回报[]?,c#,.net,ienumerable,yield,C#,.net,Ienumerable,Yield,这是一个“你可以用很多方法”的问题。考虑下面的代码: protected virtual IEnumerable<ScriptReference> GetScriptReferences() { ScriptReference referece = new ScriptReference(); referece.Assembly = "FeyenoordEnabled"; referece.Name = "FeyenoordEnabled.PassTextBo

这是一个“你可以用很多方法”的问题。考虑下面的代码:

protected virtual IEnumerable<ScriptReference> GetScriptReferences()
{
    ScriptReference referece = new ScriptReference();
    referece.Assembly = "FeyenoordEnabled";
    referece.Name = "FeyenoordEnabled.PassTextBox.js";

    return new ScriptReference[] { referece }; 
}

protected virtual IEnumerable<ScriptReference> GetScriptReferences()
{
    ScriptReference referece = new ScriptReference();
    referece.Assembly = "FeyenoordEnabled";
    referece.Name = "FeyenoordEnabled.PassTextBox.js";

    yield return referece;
}
受保护的虚拟IEnumerable GetScriptReferences()
{
ScriptReference referece=新ScriptReference();
referece.Assembly=“FeyenoordEnabled”;
referece.Name=“FeyenoordEnabled.PassTextBox.js”;
返回新的ScriptReference[]{referece};
}
受保护的虚拟IEnumerable GetScriptReferences()
{
ScriptReference referece=新ScriptReference();
referece.Assembly=“FeyenoordEnabled”;
referece.Name=“FeyenoordEnabled.PassTextBox.js”;
收益率参考;
}

我只需要返回一项。第一段代码返回一个包含单个项的数组,第二段代码生成该项什么更好?为什么?

收益率是一个非常昂贵的关键词。你告诉编译器要做很多事情。如果性能不是问题,请使用更优雅的代码。但是,如果性能有问题,请使用阵列


根据过去的经验,我可以说,摆脱这种类型的
yield
使用,我获得了一些显著的性能提升。但与往常一样,请分析并找到真正的瓶颈。

当您使用创建的数组调用它时,第一个瓶颈会直接返回

第二个,因为您使用的是yield,所以在开始获取元素之前,它甚至不会执行(在您的示例中是一个元素)


所以这实际上取决于你想做什么,但要注意不同的行为。

Profile。以下是使用mono进行的a-B比较:

public static IEnumerable<int> UsingYield()
{
    yield return 42;
}
public static IEnumerable<int> ReturningArray()
{
    return new []{ 42 };
}
阵列版本似乎简单得多:

.method public static hidebysig 
       default class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> ReturningArray ()  cil managed 
{
    // Method begins at RVA 0x2110
// Code size 12 (0xc)
.maxstack 8
IL_0000:  ldc.i4.1 
IL_0001:  newarr [mscorlib]System.Int32
IL_0006:  dup 
IL_0007:  ldc.i4.0 
IL_0008:  ldc.i4.s 0x2a
IL_000a:  stelem.i4 
IL_000b:  ret 
} // end of method Program::ReturningArray
.method公共静态隐藏
默认类[mscorlib]System.Collections.Generic.IEnumerable`1 ReturningArray()cil托管
{
//方法从RVA 0x2110开始
//代码大小12(0xc)
.maxstack 8
IL_0000:ldc.i4.1
IL_0001:newarr[mscorlib]System.Int32
IL_0006:dup
IL_0007:ldc.i4.0
IL_0008:ldc.i4.s 0x2a
IL_000a:stelem.i4
IL_000b:ret
}//方法结束程序::ReturningArray
在实际运行时性能上,配置文件

使用分析后,很明显,对单个值使用数组比使用
产生返回要快


使用.NET Core 3.1.2 x64 Windows进行测试

肯定不可能比第一个
返回
更有效吗?您也可以
返回可枚举的。重复(参考文献1)虽然这归结为封面下的
收益回报
,但我要指出
收益
还有一个用途:创建一个生成的、无休止的IEnumerable(例如,一个Fibonnaci序列生成器)。如果要这样做,就必须小心不要试图循环遍历整个IEnumerable。但是,有趣的是,我可以告诉您,出于性能原因,只要明智的话,我都会避免
收益率回报。似乎其他人正在确认这一做法。如果
收益率
如此昂贵,什么时候使用so“正确”呢?Linq基于收益率关键字的使用。yield使函数变得懒惰,如果不获取元素,则什么也不会发生。您发布的案例,直接返回是有意义的,不需要使用收益率。如果
收益率
如此昂贵,那么什么时候使用so才是“正确的”?@KeesC.Bakker:就生成的代码而言,它是复杂的。您使用它的原因在别处提到过:(a)延迟执行(b)抽象(您以程序员看不到的复杂性为代价获得状态机功能)。而且,没有人说JIT引擎不会内联相关的方法并获得接近相同的结果。简介,简介,简介!好的,先知先生……”从今天起,我要出去走走!”对于那些不想分析的人来说,C#7/.NET4.7在产生回报方面有轻微的速度优势。
.method public static hidebysig 
       default class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> ReturningArray ()  cil managed 
{
    // Method begins at RVA 0x2110
// Code size 12 (0xc)
.maxstack 8
IL_0000:  ldc.i4.1 
IL_0001:  newarr [mscorlib]System.Int32
IL_0006:  dup 
IL_0007:  ldc.i4.0 
IL_0008:  ldc.i4.s 0x2a
IL_000a:  stelem.i4 
IL_000b:  ret 
} // end of method Program::ReturningArray