Loading and parsing WinForms menus using LINQ

Posted on

Problem

I’m refactoring a WinForms utility program for building and testing regular expressions. The program has a menu item which lists the RegexOptions enumeration, allows the user to checkmark the items they want, and then those settings are applied during regex testing.

WinForms menu populated with RegexOptions

I’m rather new to LINQ, and I’d like to learn the best way to do this. At present the differences between .Cast<> and .OfType<>, .Where() and .Any() and .All() are rather ambiguous to me.

This is the code I’m using to load the menu-

menuRegexOptions.MenuItems.AddRange(
    Enum
    .GetValues(typeof(RegexOptions))
    .Cast<RegexOptions>()
    .Where(
        s => s != RegexOptions.None
    )
    .Select(
        p => new MenuItem(null, option_Click)
        {
            Text = p.ToString(),
            Tag = p
        })
    .ToArray()
    );

It works and is readable, but I’m keen to know if I’ve missed any fundamentals or can make it more efficient.

To determine the current Regex setting, the checkmarked menu items must be combined using a bitwise OR operation. The best solution I could come up with is-

public RegexOptions SelectedRegexOptions
{
    get
    {
        RegexOptions options = RegexOptions.None;

        mnuRegexOptions.MenuItems
            .Cast<MenuItem>()
            .Where(
                x => x.Checked 
            )
            .ToList()
            .ForEach(
                s => {
                    options |= (RegexOptions)s.Tag;
                } 
            );

        return options; 
    }
}

It works, but it feels like I should be able to do the != operation internally to the LINQ and then simply return the result, without the need for the external options variable.

Is there a better way?

Solution

Try this:

public RegexOptions SelectedRegexOptions
{
    get
    {
       RegexOptions options = mnuRegexOptions.MenuItems
            .Cast<MenuItem>()
            .Where(
                x => x.Checked 
            )
            .Select(s => (RegexOptions)s.Tag)
            .Aggregate(RegexOptions.None, (x, y) => x | y);

        return options; 
    }
}

The Aggregate call will take care of the bitwise ORs.

Leave a Reply

Your email address will not be published. Required fields are marked *