到目前为止,收益是我很难理解的.但现在我抓住了它.现在,在一个项目中,如果我返回List,Microsoft代码分析将发出警告.所以,通常我会做所有必要的逻辑部分并将列表作为IEnumerable返回.我想知道两者之间的区别.意味着我是否正在收益率或其他方式.
这是我展示的一个非常简单的例子,通常代码有点复杂.
private static IEnumerable<int> getIntFromList(List<int> inputList)
{
var outputlist = new List<int>();
foreach (var i in inputList)
{
if (i %2 ==0)
{
outputlist.Add(i);
}
}
return outputlist.AsEnumerable();
}
private static IEnumerable<int> getIntFromYeild(List<int> inputList)
{
foreach (var i in inputList)
{
if (i%2 == 0)
{
yield return i;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我能看到的一个重要好处是线路更少.但还有其他好处吗?我应该更改和更新返回IEnumearble以使用yield而不是List的函数吗?什么是最好的方式或更好的做事方式?
在这里,我可以在List上使用简单的lambda表达式,但通常情况并非如此,这个例子专门用于理解编码的最佳方法.
Jon*_*eet 46
您的第一个示例仍然是热切地完成所有工作并在内存中构建列表.事实上,呼吁AsEnumerable()是毫无意义的 - 你不妨使用:
return outputlist;
Run Code Online (Sandbox Code Playgroud)
你的第二个例子是懒惰的 - 当客户端从中提取数据时,它只能完成所需的工作量.
显示差异的最简单方法可能是Console.WriteLine在if (i % 2 == 0)语句中调用:
Console.WriteLine("Got a value to return: " + i);
Run Code Online (Sandbox Code Playgroud)
然后,如果你也把Console.WriteLine调用客户端代码,例如
foreach (int value in getIntFromList(list))
{
Console.WriteLine("Received value: " + value);
}
Run Code Online (Sandbox Code Playgroud)
...你会看到第一个代码,你首先看到所有"有一个值"的行,然后是所有"已接收的值"行.使用迭代器块,您将看到它们交错.
现在假设您的代码实际上做了一些昂贵的事情,而且您的列表很长,并且客户端只需要前3个值...使用您的第一个代码,您将进行大量无关的工作.使用懒惰的方法,您只需要以"及时"的方式完成所需的工作.第二种方法也不需要将所有结果缓冲到内存中 - 再次,如果输入列表非常大,您最终也会得到一个大的输出列表,即使您只想使用单个值一时间
Mar*_*ell 17
关键yield return是它没有缓冲 ; 迭代器块是一个状态机,它在迭代数据时恢复.这使得它非常适合非常大的数据源(甚至是无限列表),因为您可以避免使用大量的内存列表.
以下是一个完美定义的迭代器块,可以成功迭代:
Random rand = new Random();
while(true) yield return rand.Next();
Run Code Online (Sandbox Code Playgroud)
我们可以做以下事情:
for(int i in TheAbove().Take(20))
Console.WriteLine(i);
Run Code Online (Sandbox Code Playgroud)
虽然很明显,任何迭代到底的东西(比如Count()等)都会永远运行而不会结束 - 这不是一个好主意.
在您的示例中,代码可能过于复杂.该List<int>版本可能只是:
return new List<int>(inputList);
Run Code Online (Sandbox Code Playgroud)
该yield return还挺取决于你想要做什么:在最简单的,它可能只是:
foreach(var item in inputList) yield return item;
Run Code Online (Sandbox Code Playgroud)
虽然显然仍然会查看源数据:更改inputList可能会破坏迭代器.如果你认为"那很好",那么坦率地说你也可能只是:
return inputList;
Run Code Online (Sandbox Code Playgroud)
如果这不好,在这种情况下,迭代器块有点矫枉过正,并且:
return new List<int>(inputList);
Run Code Online (Sandbox Code Playgroud)
应该足够了.
为了完整性:AsEnumerable只返回原始源,输入类型 ; 它是:
return inputList;
Run Code Online (Sandbox Code Playgroud)
版.这有一个重要的考虑因素,因为如果这是一个问题,它不会保护您的列表.所以,如果你在想:
return someList.AsEnumerable(); // so they can only iterate it, not Add
Run Code Online (Sandbox Code Playgroud)
然后这将无法奏效; 一个邪恶的来电者仍然可以这样做:
var list = (IList<int>) theAbove;
int mwahaahahaha = 42;
list.Add(mwahaahahaha);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1889 次 |
| 最近记录: |