Некрасивая вещь и преимущество метода анонимоса -C # - PullRequest
2 голосов
/ 26 марта 2010

Меня попросили объяснить ужасную вещь и преимущества анонимного метода.

Я объяснил, возможно

Уродливая вещь

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) Безопасен ли вышеуказанный кодовый поток или нет?

Ответы [ 2 ]

7 голосов
/ 26 марта 2010

Ну, «потокобезопасный» - это довольно широкий термин. О каком многопоточном использовании вы думаете? Я бы ожидал , что это будет безопасно без какого-либо искажения данных или исключений, если ничего не будет записано в список ...

Теперь, что касается "уродства" анонимных методов ... вы используете C # 3? Если это так, начните использовать лямбда-выражения, которые, как правило, чище:

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 и т. Д. Как вы можете видеть, кода значительно больше - мне определенно потребуется больше времени, чтобы проверить это. это делает правильно, чем любой из более ранних образцов.

2 голосов
/ 26 марта 2010

Ну, все зависит от того, что вы подразумеваете под потокобезопасностью.

Если во время выполнения 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;

или, учитывая новый синтаксис лямбды, вы можете сделать это так:

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

Я знаю, какой из них я предпочитаю, но они делают разные вещи с одинаковым результатом (в данном случае.)

В первом случае вы выполняете весь код самостоятельно, никакой магии.

Во втором случае вы даете FindAll способ выяснить, какие элементы поместить в результат. Не существует неисполнимого способа сделать это, в этом случае вам нужно FindAll выполнить некоторый код, который вы укажете для каждого элемента.

...