如果为null,则Lambda表达式返回零

时间:2010-12-28 11:29:57

标签: c# lambda linq-to-objects

在我的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 个答案:

答案 0 :(得分:4)

要获取整数,可以使用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)));

答案 1 :(得分:4)

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

如果序列中没有元素,则应返回0而不是抛出异常。此外,不需要在代码中调用ToList。如果任何控件名称不是预期的格式,这仍然会抛出异常。

答案 2 :(得分:3)

由于Max()在其序列中至少需要一个元素,您必须

  • 捕获异常并将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在他的回答中指出的那样,您可以通过在查询中使用Max {{}之前的DefaultIfEmpty来避免将查询拆分为两部分。

答案 3 :(得分:0)

得到了最终答案

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

感谢Jan&amp;利