[C#] 利用LINQ和ForEach方法取代foreach

  • 26868
  • 0
  • C#
  • 2013-07-14

我們常常會使用C#中的foreach函數,對集合中的每個目標進行操作。但是,其實也可以使用LINQ搭配List的ForEach方法和Lambda陳述式來完成這個工作,會讓程式更加的簡潔許多。

 

先來看看下面的範例(雖然這次的範例用Silvelright實作,但是其實主題是C#,用Silvelright只是為了方便Demo):

 

先來看看上面範例的XAML檔,為了展現LINQ的威力,我就不一一替每個控制項命名了(其實是自己懶):

MainPage.xaml
<UserControl x:Class="CS_ReplaceForeachWithLinq.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
        Width="Auto" Height="Auto" d:DesignWidth="800" d:DesignHeight="600">

    <Border BorderThickness="2" CornerRadius="10" BorderBrush="#FF646464">

        <Grid x:Name="LayoutRoot" Background="Transparent">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="120" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="輸入欄位4:"
                    VerticalAlignment="Center" Grid.Row="4" Margin="20,0,0,0" Foreground="#FF323232"
                    FontSize="16" />
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="輸入欄位3:" Grid.Row="3"
                    d:LayoutOverrides="Height" VerticalAlignment="Center" Margin="20,0,0,0"
                    Foreground="#FF323232" FontSize="16" />
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="輸入欄位2:" Grid.Row="2"
                    d:LayoutOverrides="Height" VerticalAlignment="Center" Margin="20,0,0,0"
                    Foreground="#FF323232" FontSize="16" />
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="輸入欄位1:" Grid.Row="1"
                    d:LayoutOverrides="Height" VerticalAlignment="Center" Margin="20,0,0,0"
                    Foreground="#FF323232" FontSize="16" />
            <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
                    Text="使用Linq的ForEach方法取代傳統foreach範例" VerticalAlignment="Center"
                    Margin="25,0,0,0" Grid.ColumnSpan="2" FontSize="21.333" FontStyle="Italic"
                    Foreground="#FF323232" />
            <StackPanel HorizontalAlignment="Center" Grid.Row="5" Orientation="Horizontal"
                    Grid.ColumnSpan="2" VerticalAlignment="Center">
                <Button x:Name="btnSubmit" Content="檢查空白欄位" Width="120" Margin="10" FontSize="16"
                        Click="btnSubmit_Click" />
                <Button x:Name="btnReset" Content="重設" Width="120" Margin="10" FontSize="16"
                        Click="btnReset_Click" />
            </StackPanel>
            <TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Grid.Column="1" Grid.Row="1"
                    d:LayoutOverrides="Height" VerticalAlignment="Center" FontSize="16" Width="240"
                    BorderBrush="Black" />
            <TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Grid.Column="1" Grid.Row="2"
                    d:LayoutOverrides="Height" VerticalAlignment="Center" FontSize="16" Width="240"
                    BorderBrush="Black" />
            <TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Grid.Column="1" Grid.Row="3"
                    VerticalAlignment="Center" FontSize="16" Width="240" BorderBrush="Black" />
            <TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Grid.Column="1" Grid.Row="4"
                    d:LayoutOverrides="Height" VerticalAlignment="Center" FontSize="16" Width="240"
                    BorderBrush="Black" />
        </Grid>
    </Border>
</UserControl>

通常像上面這樣的例子,如果我們想檢查使用者介面中的每個文字輸入欄位是不是都有輸入值,並且在輸入的值是空白的時候更改文字輸入欄位的長相的話,一般應該常常會使用C#中的foreach函數,對每個目標進行操作。但是,其實也可以使用LINQ搭配List<T>的ForEach方法和Lambda陳述式來完成這個工作,會讓程式更加的簡潔許多。

然而,若使用LINQ來取得集合,預設回傳的類別會是IEnumerable<T>,而偏偏又那麼剛好,IEnumerable<T>並沒有內建ForEach方法,所以為了折衷使用,我們只得把LINQ回傳的型別轉為List<T>,再藉助它的ForEach方法來完成我們的工作。所幸,我們還有ExtensionMethod啊~~只要用ExtensionMethod幫IEnumerable<T>也加上ForEach方法就搞定啦!!

IEnumerableExtensions
public static class IEnumerableExtensions
{
    public static void ForEach<T>( this IEnumerable<T> values , Action<T> action )
    {
        foreach( var value in values )
        {
            action( value );
        }
    }
}

來看看藉助以上提到的語法,程式可以怎麼寫:

MainPage.xaml.cs
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace CS_ReplaceForeachWithLinq
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void btnSubmit_Click( object sender , RoutedEventArgs e )
        {
            //在使用ForEach方法之前,可能得用像以下的寫法
            /*
            var textBoxes = this.LayoutRoot.Children.OfType<TextBox>().Where( t => t.Text.Length == 0 );

            foreach( TextBox textBox in textBoxes )
            {
                textBox.BorderBrush = new SolidColorBrush { Color = Colors.Red }; 
                textBox.Background = new SolidColorBrush { Color = Colors.Orange };
            }
            */

            //在沒使用ExtensionMethod之前,得先轉成List才可以使用ForEach方法
            this.LayoutRoot.Children.OfType<TextBox>().Where( t => t.Text.Length == 0 ).ToList<TextBox>().ForEach( t => 
            { 
                t.BorderBrush = new SolidColorBrush { Color = Colors.Red }; 
                t.Background = new SolidColorBrush { Color = Colors.Orange }; 
            } );
        }

        private void btnReset_Click( object sender , RoutedEventArgs e )
        {
            //使用ExtensionMethod,只要這樣就可以搞定了
            this.LayoutRoot.Children.OfType<TextBox>().ForEach( t => 
            { 
                t.Text = string.Empty; t.Background = new SolidColorBrush { Color = Colors.White }; 
                t.BorderBrush = new SolidColorBrush { Color = Colors.Black }; 
            } );
        }
    }
}

以上,好不好用就見仁見智囉!!跟大家分享,有興趣的人也可以試著這樣寫看看喔~

最後一樣附上原始碼,請自行服用: