2

我被要求解释匿名方法的丑陋之处和优点。

我解释了可能

丑陋的东西

anonymous methods turning quickly into spaghetti code.

好处

我们可以使用匿名方法生成线程安全代码:示例

static List<string> Names = new List<string>(
  new string[] {
    "Jon Skeet",
    "Marc Gravell",
    "David",
    "Bill  Gates"
  });

static List<string> FindNamesStartingWith(string startingText)
{
  return Names.FindAll(
    delegate(string name)
    {
      return name.StartsWith(startingText);
    });
}

但实际上我不知道它是否是线程安全的。我被要求证明它的合理性。谁能帮我理解 (1)匿名方法的优点(2)上面的代码线程安全吗?

4

2 回答 2

7

好吧,“线程安全”是一个相当广泛的术语。你在想什么样的多线程使用?如果没有任何内容写入列表,我希望它是安全的,没有任何数据损坏或异常......

现在,至于匿名方法的“丑陋”……您使用的是 C# 3 吗?如果是这样,请开始使用 lambda 表达式,它们通常更简洁:

static List<string> FindNamesStartingWith(string startingText)
{
    return Names.FindAll(name => name.StartsWith(startingText));
}

或者,使用 LINQ:

static List<string> FindNamesStartingWith(string startingText)
{
    return Names.Where(name => name.StartsWith(startingText)).ToList();
}

或者,如果您不一定需要列表:

static IEnumerable<string> FindNamesStartingWith(string startingText)
{
    return Names.Where(name => name.StartsWith(startingText));
}

或者,如果您更喜欢查询表达式:

static IEnumerable<string> FindNamesStartingWith(string startingText)
{
    return from name in names
           where name.StartsWith(startingText)
           select name;
}

在我看来,这些都不像意大利面条代码。但是,如果你要问是否应该使用这个或其他东西,你真的应该提出一个替代方案。这是一个简单的:

static List<string> FindNamesStartingWith(string startingText)
{
    List<string> ret = new List<string>();
    foreach (string name in Names)
    {
        if (name.StartsWith(startingText))
        {
            ret.Add(name);
        }
    }
    return ret;
}

你觉得这更清楚吗?如果是这样,那很好——但我怀疑这只是你对匿名函数、LINQ 等不太熟悉。正如你所看到的,代码要多得多——检查它是否做正确的事情肯定会花费我更长的时间任何早期的样本。

于 2010-03-26T19:35:03.120 回答
2

好吧,这完全取决于线程安全的含义。

如果在执行期间FindAll,其他一些线程更改了基础Names集合,那么您可能会得到奇怪的结果。

对多个线程的多次调用FindAll本身是否安全,也就是说,只有它们执行?是的,这是肯定的。

至于匿名方法的优点,请考虑替代方案。

你想要:

  1. 查找集合中的一些项目
  2. 知道要查找哪个项目的唯一方法是为每个项目评估一些表达式

你可以这样做:

List<string> result = new List<string>();
foreach (string name in Names)
    if (name.StartsWith(startingText))
        result.Add(name);
return result;

或者,给定新的 lambda 语法,您可以这样做:

return Names.FindAll(name => name.StartsWith(startingText));

我知道我更喜欢哪一个,但他们做不同的事情,结果相同(在这种情况下)。

在第一种情况下,您自己执行所有代码,没有魔法。

在第二种情况下,您提供了FindAll一种方法来确定将哪些项目放入结果中。在这种情况下,没有不可执行的方法可以做到这一点,您需要FindAll为每个项目执行一些您指定的代码。

于 2010-03-26T19:37:36.850 回答