Лямбда-выражение для возврата нуля, если ноль - PullRequest
4 голосов
/ 28 декабря 2010

в моем приложении WPF я использовал для динамического добавления элементов управления в Canvas. Формат имени элемента управления - «Control_UniqueValue».

Т.е., если я добавлю первый элемент управления к холсту, то имя будет "Control_1", а следующим будет "Control_2" и т. Д. ...

Мое требование - получить максимальное значение добавленных элементов управления

я использовал следующее утверждение для этого

string maxId = (string)canvas1.Children.Cast<FrameworkElement>().ToList().Max(x => (x.Name.Substring(x.Name.LastIndexOf('_') + 1)));

но проблема здесь

  1. необходимо вернуть значение как int

  2. если холст не содержит элементов управления, это вызовет ошибку (пробовал использовать тип Nullable, но не удалось)

Ответы [ 4 ]

4 голосов
/ 28 декабря 2010
int  maxId = canvas1.Children
    .Cast<FrameworkElement>()
    .Select(e => int.Parse(e.Name.Substring(e.Name.LastIndexOf('_'))))
    .DefaultIfEmpty()
    .Max();

Это должно возвратить 0 вместо броска исключения, если в последовательности нет элементов. Также звонок на ToList в вашем коде не обязателен. Это все равно вызовет исключение, если любое из имен элементов управления не в ожидаемом формате.

4 голосов
/ 28 декабря 2010

Чтобы получить целое число, вы можете использовать метод int.Parse.Вам не нужно звонить ToList().

Нет проверки ошибок, поэтому ваши элементы управления должны быть названы относительно вашего правила name_id.

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

int maxId = canvas1.Children
             .Cast<FrameworkElement>()
             .DefaultIfEmpty(new FrameworkElement() { Name = "Control_0" })
             .Max(x => (int.Parse(x.Name.Split('_')[1]) + 1)));
3 голосов
/ 28 декабря 2010

Поскольку Max () требует хотя бы один элемент в своей последовательности, вы должны либо

  • перехватить исключение и установить максимальное значение в ноль
  • проверьте длину перед вызовом Max (). Я бы порекомендовал это

Хотя можно написать логику в одном длинном выражении запроса, я бы порекомендовал немного разбить его, чтобы улучшить читаемость. Создайте метод, который возвращает целочисленную часть имени дочернего элемента управления:

private int NumberFromElementName(string name)
{
    // Or search for the last '_' using name.LastIndexOf()
    var numString = name.Substring("Control_".Length);
    return Int32.Parse(numString);
}

Затем выполните запрос в два шага, чтобы увидеть длину возвращаемой последовательности. Заметьте, я конвертирую его в массив, чтобы избежать необходимости дважды выполнять запрос. Я также использую метод расширения OfType , чтобы он работал, даже если у холста есть дочерний элемент, который не относится к типу FrameworkElement.

var children = canvas1.Children.OfType<FrameworkElement>().ToArray();
int max = 0;
if (children.Length > 0)
    max = children.Max(x => NumberFromElementName(x.Name));
string nextChildName = String.Format ("Control_{0}", max + 1);

РЕДАКТИРОВАТЬ: Как указал @Jan в своем ответе, вы можете избежать разделения запроса на две части, используя DefaultIfEmpty перед вызовом Max в запросе.

0 голосов
/ 28 декабря 2010

получил окончательный ответ

int maxId = canvas1.Children .Cast<FrameworkElement>() .Select(e => int.Parse(e.Name.Substring(e.Name.LastIndexOf('_')+ 1))) .DefaultIfEmpty() .Max(x => x + 1); 

Спасибо, Ян и Ли

...