我遇到了一个匿名委托的问题,我用它来构建集合的子集。
当时我坚持使用.Net Framework 2.0,所以不使用LINQ而是必须创建一些辅助函数来创建这些子集。
大多数情况下它工作正常,但似乎我不理解该委托的闭包,因为当它在范围之外进行评估时失败。
幸运的是,我设法在下面创建了一个显示问题的简单示例。
我已经实现了两个版本的迭代器。基本上总是工作的那个,不使用委托。并且使用它的人只能在内在的范围内工作。
我只是想知道为什么我不能依赖使用委托的实现,因为我打算将结果存储在变量中,并且我希望确保内容不会因为范围问题而改变。
更新:根据建议,将示例更改为控制台应用以使其更实用。删除了调试代码并缩短了列表长度。
下面是示例代码:
using System;
using System.Collections.Generic;
using System.Text;
namespace YuDoThisStap
{
class Program
{
static void Main(string[] args)
{
List<string> variables = new List<string>();
variables.Add("ab 12");
variables.Add("cd 23");
variables.Add("ef 34");
variables.Add("gh 45");
variables.Add("ij 67");
variables.Add("kl 78");
variables.Add("mn 89");
variables.Add("op 90");
List<int> numbers = new List<int>();
for (int n = 0; n < 10; n++)
numbers.Add(n);
List<char> characters = new List<char>();
for (char c = 'a'; c < 'p'; c++)
characters.Add(c);
Dictionary<string, IEnumerable<string>> results = new Dictionary<string, IEnumerable<string>>();
foreach (int n in numbers)
{
foreach (char c in characters)
{
IEnumerable<string> result = Select<string>(variables, delegate(string s) { return s.Contains(c.ToString()) && s.Contains(n.ToString()); });
//IEnumerable<string> result = ByNumber(ByCharacter(variables, c), n);
int count = 0;
foreach (string str in result)
count++;
if (count > 0)
{
string desc = "";
foreach (string v in result)
desc += v;
results.Add(string.Format("Condition (char = '{0}'; number = {1}, original = '{2}'):", c, n, desc), result);
}
}
}
// Report results
foreach (KeyValuePair<string, IEnumerable<string>> item in results)
{
Console.WriteLine(item.Key);
foreach (string v in item.Value)
Console.WriteLine("\t" + v);
}
}
public delegate TResult Func<TArg0, TResult>(TArg0 arg0);
public static IEnumerable<string> ByCharacter(IEnumerable<string> source, char character)
{
foreach (string element in source)
if (element.Contains(character.ToString()))
yield return element;
}
public static IEnumerable<string> ByNumber(IEnumerable<string> source, int number)
{
foreach (string element in source)
if (element.Contains(number.ToString()))
yield return element;
}
public static IEnumerable<T> Select<T>(IEnumerable<T> source, Func<T, bool> predicate)
{
foreach (T element in source)
if (predicate(element))
yield return element;
}
}
}
更新2 :我进一步简化了删除两个列表并看起来像是因为我正在使用在for / foreach中创建的变量。如果我创建一个时间变量,它可以工作,否则它比原始代码更差。
Dictionary<string, IEnumerable<string>> results = new Dictionary<string, IEnumerable<string>>();
for (int n = 0; n < 10; n++)
{
for (char c = 'a'; c < 'p'; c++)
{
char c2 = c;
int n2 = n;
IEnumerable<string> result = Select<string>(variables, delegate(string s)
{
return s.Contains(c2.ToString()) && s.Contains(n2.ToString());
});
//IEnumerable<string> result = ByNumber(ByCharacter(variables, c), n);
int count = 0;
foreach (string str in result) count++;
if (count > 0)
{
string desc = "";
foreach (string v in result) desc += v;
results.Add(string.Format("Condition (char = '{0}'; number = {1}, original = '{2}'):", c, n, desc), result);
}
}
}