C# 奇怪的委托引用行为
我需要将源函数的结果(返回一个C# 奇怪的委托引用行为,c#,delegates,reference,ienumerable,stack-overflow,C#,Delegates,Reference,Ienumerable,Stack Overflow,我需要将源函数的结果(返回一个IEnumerable)传递给其他处理函数的列表(每个处理函数接受并返回一个IEnumerable) 在这一点上一切都很好,但我还需要允许处理函数在其输入枚举上执行多个循环 因此,我不想传入IEnumerable,而是想将输入参数更改为Func,并允许每个函数在需要时重新启动枚举 不幸的是,我现在遇到了堆栈溢出,最终的处理函数正在调用自己,而不是将请求传递回链 示例代码有点做作,但希望能让您了解我试图实现的目标 class Program { public
IEnumerable
)传递给其他处理函数的列表(每个处理函数接受并返回一个IEnumerable
)
在这一点上一切都很好,但我还需要允许处理函数在其输入枚举上执行多个循环
因此,我不想传入IEnumerable
,而是想将输入参数更改为Func
,并允许每个函数在需要时重新启动枚举
不幸的是,我现在遇到了堆栈溢出,最终的处理函数正在调用自己,而不是将请求传递回链
示例代码有点做作,但希望能让您了解我试图实现的目标
class Program
{
public static void Main(string[] args)
{
Func<IEnumerable<String>> getResults = () => GetInputValues("A", 5);
List<String> valuesToAppend = new List<String>();
valuesToAppend.Add("B");
valuesToAppend.Add("C");
foreach (var item in valuesToAppend)
{
getResults = () => ProcessValues(() => getResults(),item);
}
foreach (var item in getResults())
{
Console.WriteLine(item);
}
}
public static IEnumerable<String> GetInputValues(String value, Int32 numValues)
{
for (int i = 0; i < numValues; i++)
{
yield return value;
}
}
public static IEnumerable<String> ProcessValues(Func<IEnumerable<String>> getInputValues, String appendValue)
{
foreach (var item in getInputValues())
{
yield return item + " " + appendValue;
}
}
}
类程序
{
公共静态void Main(字符串[]args)
{
Func getResults=()=>GetInputValues(“A”,5);
List valuesToAppend=新列表();
附加价值。添加(“B”);
附加价值。添加(“C”);
foreach(valuesToAppend中的var项目)
{
getResults=()=>ProcessValues(()=>getResults(),项);
}
foreach(getResults()中的var项)
{
控制台写入线(项目);
}
}
公共静态IEnumerable GetInputValue(字符串值、Int32 numValue)
{
for(int i=0;i
getResults
被捕获为变量,而不是值。我真的不喜欢您在这里使用的整体方法(看起来很复杂),但您应该能够通过更改捕获来修复stackoverflow:
foreach (var item in valuesToAppend)
{
var tmp1 = getResults;
var tmp2 = item;
getResults = () => ProcessValues(() => tmp1(),tmp2);
}
另一方面:IEnumerable[]
已经有点可重复了,您只需另一次调用foreach
即可-这是IEnumerator[]
(尽管Reset()
)不是-而且,我认为在不需要重复枚举的情况下尝试这样做是值得的,因为在一般情况下,这根本不能保证有效
下面是一个更简单的(IMO)实现,具有相同的结果:
using System;
using System.Collections.Generic;
using System.Linq;
class Program {
public static void Main() {
IEnumerable<String> getResults = Enumerable.Repeat("A", 5);
List<String> valuesToAppend = new List<String> { "B", "C" };
foreach (var item in valuesToAppend) {
string tmp = item;
getResults = getResults.Select(s => s + " " + tmp);
}
foreach (var item in getResults) {
Console.WriteLine(item);
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
班级计划{
公共静态void Main(){
IEnumerable getResults=可枚举。重复(“A”,5);
List valuesToAppend=新列表{“B”,“C”};
foreach(valuesToAppend中的var项目){
字符串tmp=项目;
getResults=getResults.Select(s=>s+“”+tmp);
}
foreach(getResults中的var项){
控制台写入线(项目);
}
}
}
第一个示例避免了堆栈溢出,但现在返回:ACC、ACC等。谢谢。现在开始工作!现实世界中的处理代码需要处理内存中的大量项,因此需要多次传递才能在内存不足的情况下工作。我还没有意识到IEnumerable足够聪明,可以自己重复——有什么理由我不应该依赖这种行为吗?@rob-yes;它完全取决于枚举器的底层实现。例如,我可能会编写一个枚举器,从打开的套接字中提取数据,但不能重复。或者,如果我是邪恶的,我可以编写一个枚举器,从随机
实例中提取数据,或者Guid
-如果你可以重复这些,那么你做得很好。@rob-这些问题会以完全相同的方式影响基于函数的代码。因此,您增加了一层复杂性,但没有解决问题。源始终是磁盘读取(在方法内部重置位置),因此我很乐意使用更简单的选项并放弃代理。谢谢你的帮助,马克。