2013年9月11日 星期三

[轉貼] 利用Dictionary集合和委派完整移除if else的分支判斷


原本的if else寫法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightApplication3
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            string userInput = "櫻桃";//使用者輸入的文字

            if (userInput == "蘋果")
            {
                showApple();
            }
            else if (userInput == "香蕉")
            {
                showBanana();

            }
            else if (userInput == "櫻桃")
            {
                showCherry();

            }
         
        }
        private void showApple()
        {
            //Do Apple something...
            MessageBox.Show("Apple");
        }
        private void showBanana()
        {
            //Do Banana something...
            MessageBox.Show("Banana");
        
        }
        private void showCherry()
        {
            //Do Cherry something...
            MessageBox.Show("Cherry");
        }
    }

}
雖然先前提過[C#] 用反射(映射)移除if…else陳述式
可以用反射來移除if分支,但要是遇到輸入的字串是中文字,程式碼就得跟著使用中文命名,感覺怪怪的↓…
string userInput = "櫻桃";//使用者輸入的文字

Type t = Type.GetType("SilverlightApplication3.MyUserControl");
//拼接要執行method的名稱(中文)
string methodName = "嘻嘻哈哈";
object result = t.InvokeMember(methodName, BindingFlags.InvokeMethod, null, Activator.CreateInstance(t), null);
條件是字串的判斷
今天剛好遇到要寫很多分支條件判斷,發現如果只是單純的中文字串,應該可以把 條件和要做的Method 都先放入Dictionary中
再依據使用者輸入的字串,直接挑出目標Method來執行就好
所以上述程式碼可以改良(具名委派版)↓
public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }
        public delegate void DoSomething();//宣告委派
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            string userInput = "櫻桃";//使用者輸入的文字
            //把原本if要判斷的條件字串儲存在Key,由於原本的if條件本來就不會重覆,正適合當Key
            //各個Key(條件)要執行的Method就儲存在Value
            Dictionary<string, DoSomething> d = new Dictionary<string, DoSomething>()
            {
            {"蘋果", new DoSomething(showApple)},
            {"香蕉", new DoSomething(showBanana)},
            {"櫻桃", new DoSomething(showCherry)}};
            d[userInput].Invoke();//直接挑選要執行的Method來執行

        }
        private void showApple()
        {
            //Do Apple something...
            MessageBox.Show("Apple");
        }
        private void showBanana()
        {
            //Do Banana something...
            MessageBox.Show("Banana");
        }
        private void showCherry()
        {
            //Do Cherry something...
            MessageBox.Show("Cherry");
        }
    }
如果懶得宣告具名委派,寫得更簡潔的話↓
public partial class MainPage : UserControl
   {
       public MainPage()
       {
           InitializeComponent();
       }
      
       private void UserControl_Loaded(object sender, RoutedEventArgs e)
       {
           string userInput = "櫻桃";//使用者輸入的文字

           Dictionary<string, Action> d = new Dictionary<string, Action>() {
           {"蘋果",  ()=>{ MessageBox.Show("Apple");  }}, //各條件要做的事....
           {"香蕉",  ()=>{ MessageBox.Show("Banana");  }},
           {"櫻桃",  ()=>{ MessageBox.Show("Cherry");  }}
           };
           
           d[userInput].Invoke();//直接挑選要執行的Method來執行
           
       }
  
   }
↑如此一來,各條件要做的事都很整齊地列出來,Code也變得比較乾淨。
條件是數字大小的判斷
但「if 也有判斷數字區間的情況,該怎麼辦呢?」
例如以下:
public partial class MainPage : UserControl
   {
       public MainPage()
       {
           InitializeComponent();
       }
      
       private void UserControl_Loaded(object sender, RoutedEventArgs e)
       {
           int userInput = 14;//使用者輸入的文字

           if (userInput >= 1 && userInput <= 10)//在1到10的區間
           {
               showApple();
           }
           else if (userInput >= 11 && userInput <= 20)//在11到20的區間
           {
               showBanana();
           }
           else if (userInput >= 21 && userInput <= 30)//在21到30的區間
           {
               showCherry();
           }
       
           
       }
       private void showApple()
       {
           //Do Apple something...
           MessageBox.Show("Apple");
       }
       private void showBanana()
       {
           //Do Banana something...
           MessageBox.Show("Banana");

       }
       private void showCherry()
       {
           //Do Cherry something...
           MessageBox.Show("Cherry");
       }
  
   }
基本上也可以用Dictionary,也是把條件放在Key的位置,要做的事放在Value
條件式會回傳true Or false,所以就可以利用Linq挑選出Key回傳值為true的Value(Method)來執行即可
如下:
public partial class MainPage : UserControl
   {
       public MainPage()
       {
           InitializeComponent();
       }
       public delegate bool MyKey(int userInput);
       public delegate void MyValue();
       private void UserControl_Loaded(object sender, RoutedEventArgs e)
       {
           int userInput = 14;//使用者輸入的文字

           Dictionary<MyKey, MyValue> d = new Dictionary<MyKey, MyValue>()
           {
            {new MyKey(condition1),  new MyValue(showApple) },//各條件要做的事....
            {new MyKey(condition2),  new MyValue(showBanana)},
            {new MyKey(condition3),  new MyValue(showCherry)},
           
           };



           //挑選出Key的回傳值為true的Method來執行
           d.Where(x => x.Key(userInput) == true).FirstOrDefault().Value.Invoke();
           
             
       }   
       //把條件抽出成Method
       private bool condition1(int i)
       {
        return (i>=1 && i<=10);
       }
       private bool condition2(int i)
       {
           return (i >= 11 && i <= 20);
       }
       private bool condition3(int i)
       {
           return (i >= 21 && i <= 30);
       }
       private void showApple()
       {
           //Do Apple something...
           MessageBox.Show("Apple");
       }
       private void showBanana()
       {
           //Do Banana something...
           MessageBox.Show("Banana");

       }
       private void showCherry()
       {
           //Do Cherry something...
           MessageBox.Show("Cherry");
       }
   
   }
簡潔寫法:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
       {
           int userInput = 14;//使用者輸入的文字

           Dictionary<Func<int, bool>, Action> d = new Dictionary<Func<int, bool>, Action>() {
           { (a)=>{return (a >= 1 && a <= 10);},  ()=>{ MessageBox.Show("Apple");  }}, //各條件要做的事....
           { (a)=>{return (a >= 11 && a <= 20);},  ()=>{ MessageBox.Show("Banana");  }},
           { (a)=>{return (a >= 21 && a <= 30);},  ()=>{ MessageBox.Show("Cherry");  }}
           };
           //挑選出Key回傳值為true的Method來執行
           d.Where(x => x.Key(userInput) == true).FirstOrDefault().Value.Invoke();

           
       }
多個條件符合的判斷
看完以上兩個例子,再來假設一點
如果有符合多個條件的情況,如下:
public partial class MainPage : UserControl
   {
       public MainPage()
       {
           InitializeComponent();
       }
       //這次把else移掉,每個if都會進行判斷,並且有兩個條件符合
       private void UserControl_Loaded(object sender, RoutedEventArgs e)
       {
           int userInput = 14;//使用者輸入的文字
           
           if(userInput>0)
           {
               showPlus();
           }
           if (userInput >= 1 && userInput <= 10)//在1到10的區間
           {
               showApple();
           }
           if (userInput >= 11 && userInput <= 20)//在11到20的區間
           {
               showBanana();
           }
            if (userInput >= 21 && userInput <= 30)//在21到30的區間
           {
               showCherry();
           }
       
           
       }
       private void showPlus()
       {
            //Do plus something...
           MessageBox.Show("Plus");

       }
       private void showApple()
       {
           //Do Apple something...
           MessageBox.Show("Apple");
       }
       private void showBanana()
       {
           //Do Banana something...
           MessageBox.Show("Banana");

       }
       private void showCherry()
       {
           //Do Cherry something...
           MessageBox.Show("Cherry");
       }
  
   }
也是可以改寫成如下:
public partial class MainPage : UserControl
  {
      public MainPage()
      {
          InitializeComponent();
      }
      public delegate bool MyKey(int userInput);
      public delegate void MyValue();
      private void UserControl_Loaded(object sender, RoutedEventArgs e)
      {
          int userInput = 14;//使用者輸入的文字

          Dictionary<MyKey, MyValue> d = new Dictionary<MyKey, MyValue>()
          {
           {new MyKey(isPlus), new MyValue(showPlus)},
           {new MyKey(condition1),  new MyValue(showApple) },//各條件要做的事....
           {new MyKey(condition2),  new MyValue(showBanana)},
           {new MyKey(condition3),  new MyValue(showCherry)},
           
          };


          //※只是把原本的.FirstOrDefault(),改成foreach走訪每筆物件,並在迴圈中執行Method即可
          //挑選出Key回傳值為true的Method來執行,並注意集合內的物件順序就是Method執行順序
          foreach (KeyValuePair<MyKey,MyValue> item in d.Where(x => x.Key(userInput) == true))
          {
              item.Value.Invoke();
          }

      }
      //把條件抽出成Method
      private bool isPlus(int i)
      {
          return i > 0;
      }
      private bool condition1(int i)
      {
          return (i >= 1 && i <= 10);
      }
      private bool condition2(int i)
      {
          return (i >= 11 && i <= 20);
      }
      private bool condition3(int i)
      {
          return (i >= 21 && i <= 30);
      }
      private void showPlus()
      {
       //Do plus something...
          MessageBox.Show("Plus");
      }
      private void showApple()
      {
          //Do Apple something...
          MessageBox.Show("Apple");
      }
      private void showBanana()
      {
          //Do Banana something...
          MessageBox.Show("Banana");

      }
      private void showCherry()
      {
          //Do Cherry something...
          MessageBox.Show("Cherry");
      }

  }
簡潔寫法:
public partial class MainPage : UserControl
   {
       public MainPage()
       {
           InitializeComponent();
       }
        
      
       private void UserControl_Loaded(object sender, RoutedEventArgs e)
       {

           int userInput = 14;//使用者輸入的文字

           Dictionary<Func<int, bool>, Action> d = new Dictionary<Func<int, bool>, Action>() {
           {(a)=>{ return (a > 0);}            ,   ()=>{ MessageBox.Show("Plus");   }},
           { (a)=>{return (a >= 1 && a <= 10);},   ()=>{ MessageBox.Show("Apple");  }}, //各條件要做的事....
           { (a)=>{return (a >= 11 && a <= 20);},  ()=>{ MessageBox.Show("Banana");  }},
           { (a)=>{return (a >= 21 && a <= 30);},  ()=>{ MessageBox.Show("Cherry");  }}
           };


           //※只是把原本的.FirstOrDefault(),改成foreach走訪每筆物件,並在迴圈中執行Method即可
           //挑選出Key回傳值為true的Method來執行
           foreach (KeyValuePair<Func<int, bool>, Action> item in d.Where(x => x.Key(userInput) == true))
           {
               item.Value.Invoke();
           }

       }


   }
複合式條件的判斷
如果原本的if else要判斷的條件很複雜,如下:
..............(略,看原文)

沒有留言:

張貼留言