Lambda expression returns zero if null

in my WPF application that I used to dynamically add controls to Canvas. The format of the control name is "Control_UniqueValue".

ie, if I add the first control to the canvas, then the name will be "Control_1", and the next will be "Control_2", etc ....

my requirement is to get the maximum value of the added controls

I used the following statement for this

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

but the problem is here

  • need to return the value as int

  • if there are no controls in the canvas, it will cause an error (using the Nullable type, but with an error)

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

This should return 0 instead of throwing an exception if there are no elements in the sequence. In addition, a ToList call is not required in your code. This will still throw an exception if any of the control names are not in the expected format.

+4
source

To get an integer, you can use the int.Parse method. You do not need to call ToList() .

Error checking error, so your controls should be specified in accordance with your name_id rule.

You can use the DefaultIfEmpty extension DefaultIfEmpty to provide a default value if the sequence is empty:

 int maxId = canvas1.Children .Cast<FrameworkElement>() .DefaultIfEmpty(new FrameworkElement() { Name = "Control_0" }) .Max(x => (int.Parse(x.Name.Split('_')[1]) + 1))); 
+4
source

Since Max () requires at least one element in its sequence, you must either

  • catch the exception and set max to zero
  • check the length before calling Max (). I would recommend this

Although you can write the logic in one long query expression, I would recommend that you figure it out a bit to improve readability. Create a method that returns the integer part of the child control:

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

Then complete the query in two steps so that you can see the length of the returned sequence. Note that I convert it to an array to avoid having to run the query twice. I also use the OfType extension method to make it work even if there is a child in the canvas that is not of type 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); 

EDIT: As @Jan noted in his answer, you can avoid splitting the request in two parts by using DefaultIfEmpty before calling Max in the request.

+3
source

got the final answer

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

Thanks Yang and Lee

0
source

Source: https://habr.com/ru/post/1333562/


All Articles