Если оператор внутри лямбда-функции? - PullRequest
5 голосов
/ 03 июня 2009

Это может быть довольно просто, но я довольно новичок в Лямбде, так что терпите меня.

У меня есть функция, которая использует лямбда-функцию для рекурсии. Основная функция получает логическое значение, говорящее, что она включает определенную информацию или нет в лямбду.

Функция предназначена для записи пользовательского класса в XML - я думаю, что код довольно понятен.

В данный момент я преодолел проблему, используя простое утверждение if, но мне страшно интересно, кто-нибудь знает лучший способ?

        private XElement ErrorListToXml(ErrorList el, bool outputTagsOnly)
    {
        // Need to declare in advance to call within the lambda.
        Func<ErrorType, XElement> recursiveGenerator = null;

        if (outputTagsOnly)
            recursiveGenerator = error => new XElement
                (error.Name,
                 error.ChildErrors.Select(recursiveGenerator));
        else
            recursiveGenerator = error => new XElement
          (error.Name,
          new XAttribute("Ignore", error.Filter),
           error.ChildErrors.Select(recursiveGenerator));


        var element = new XElement
                   ("ErrorList",
                    ChildErrors.Select(recursiveGenerator));

        Console.WriteLine(element);

        return element;
    }

Ответы [ 5 ]

6 голосов
/ 03 июня 2009
Решение

mquander можно немного улучшить, чтобы уменьшить дублирование. Вы можете использовать тот факт, что вы можете передать null элемент в содержимом конструктора XElement, и он игнорируется Поэтому мы можем продвинуть условие дальше:

Func<ErrorType, XElement> recursiveGenerator = null;    
recursiveGenerator = (error => new XElement(error.Name,
            outputTagsOnly ? null : new XAttribute("Ignore", error.Filter),
            error.ChildErrors.Select(recursiveGenerator));

var element = new XElement("ErrorList", ChildErrors.Select(recursiveGenerator));
6 голосов
/ 03 июня 2009

Вы можете довольно легко принять решение между значениями одного и того же типа в лямбде:

customer => flag ? customer.Name : customer.Address

Вы можете использовать оператор if в лямбда-выражении с небольшим усилием:

customer =>
{
  if (flag)
    return customer.Name
  else
    return customer.Address
}

Ничто из этого не поможет вашему методу.

6 голосов
/ 03 июня 2009

Вы можете безопасно переместить оператор if внутри лямбда-функции, если предпочитаете:

Func<ErrorType, XElement> recursiveGenerator = null;

recursiveGenerator = (error =>
    outputTagsOnly
        ? new XElement(error.Name,
                       error.ChildErrors.Select(recursiveGenerator));
        : new XElement(error.Name, new XAttribute("Ignore", error.Filter),
                       error.ChildErrors.Select(recursiveGenerator)));

var element = new XElement("ErrorList", ChildErrors.Select(recursiveGenerator));

Кроме этого, кажется, нет простого способа упростить то, что у вас есть.

(P.S. Когда это выглядит некрасиво, нанесите немного помады на эту свинью, просто напечатав ее;)

0 голосов
/ 03 июня 2009

Вы можете попытаться разложить вашу проблему на две разные:

  1. Как построить дерево из структуры ошибок.
  2. Что поместить в узлы дерева.

Тогда код будет выглядеть так:

        private XElement ErrorListToXml(ErrorList el, bool outputTagsOnly)
        {
            // Need to declare in advance to call within the lambda.
            Func<ErrorType, XElement> treeGenerator = null;
            Func<ErrorType, object[]> elementParametersGenerator = null;

            treeGenerator = error => new XElement
                (error.Name,
                elementParametersGenerator(error));

            if(outputTagsOnly)
                elementParametersGenerator = error => 
                    new object[] {error.ChildErrors.Select(treeGenerator)};
            else
                elementParametersGenerator = error => 
                    new object[] { new XAttribute("Ignore", error.Filter), error.ChildErrors.Select(treeGenerator) };

            var element = new XElement
                       ("ErrorList",
                        ChildErrors.Select(treeGenerator));

            Console.WriteLine(element);

            return element;
        }

Не намного лучше в данном конкретном случае, но это более общий подход.

0 голосов
/ 03 июня 2009

Полагаю, вы можете сделать это, но в конце дня все равно будет if:

                recursiveGenerator = error => outputTagsOnly ? 
                   new XElement(error.Name,error.ChildErrors.Select(recursiveGenerator)
              : 
              new XElement(error.Name,new XAttribute("Ignore", error.Filter), 
             error.ChildErrors.Select(recursiveGenerator);
...