2013年4月30日 星期二

委派Delegate教學

本文參考
http://rfid-fantasy.blogspot.tw/2009/07/c-delegate.html
http://big5.webasp.net/article/6/5592_print.htm
http://blog.xuite.net/johnnyle/worker/16891057
http://www.dotblogs.com.tw/yc421206/archive/2009/02/16/7206.aspx
關於Delegate 理論上用於,代理類別的一種技巧
用於物件導向,類別與方法
簡單來說 就是代理呼叫的意思,而類別中也可以使用委派
而委派也已再次委派 下面直接看範例

在範例之前 紀錄一下 運行原理!

假如要用Delegate寫一個簡易計算機程式
原理則是
先建立 +-*/ 4大類別
在宣告委派Delegate
編輯完後
在觸發控制項中
建立Delegate 指定為null值,稍後在實體化,並指派方法
建立2個數值型態放數字
與1個字串型態放+-*/字元
再利用switch 判斷 輸入的字串為和??
再利用case 做字元判斷
判斷成功 將委派物件實體化並且 指定類別
委派設定完後~
將套入數值參數   \\數值型態=委派(數值參數)
當委派套入數值參數時,委派將呼叫剛才指定的類別
並且將參數傳給類別,類別運算完之後 return給委派
委派再給 新宣告的 數值型態
數值型態在SHOW出給使用者運算結果!
來看CODING!

首先 先建立 委派 跟 類別

delegate int GGYY(int GG, int YY);//先宣告等等要呼叫的委派叫GGYY
//在這邊要注意 委派的參數 型態必須與呼叫的方法 是一樣的
        //下面宣告4個方法 注意 傳入參數的型態必須一樣
        private int addd(int a, int b)//宣告方法
        {
            //加
            return a + b;//回傳a+b
        }
        private int subtract(int a, int b)
        {
            //減
            return a - b;
        }
        private int multiply(int a, int b)
        {
            //乘
            return a * b;
        }
        private int divide(int a, int b)
        {
            //除
            return a / b;
        }
再來我們在 控制項中 來運用委派 控制項是BUTTON

private void button5_Click(object sender, EventArgs e)
        {
            GGYY ARI=null;//如果不指定個NULL直 編識器會發生錯誤
            //錯誤是Use of unassigned local variable 'ARI' 沒有初始化ari
            //所以要給一個null直 但不能是 數值 因為是delegate委派方法
            string FUN = textBox2.Text;//輸入加減乘除+-*/
            int x = int.Parse(textBox1.Text);//輸入 計算數值1
            int y = int.Parse(textBox3.Text);//輸入計算數值2
            switch (FUN)//判斷FUN是輸入什麼?
            {//索取輸入FUN的運算子    然後先建立所指定的物件
                case "+":
                    ARI = new GGYY(addd);//如果是用add必須+THIS 複寫ADD
                    break;
                case "-":
                    ARI = new GGYY(subtract);
                    break;
                case "*":
                    ARI = new GGYY(multiply);
                    break;
                case "/":
                    ARI = new GGYY(divide);//實作委派
                    break;
            }
            //建立好之後 ARI帶入X,Y直 呼叫委派
            //呼叫的哪一個委派物件決定剛剛SWITCH所選擇的物件
            int anser = ARI(x, y);//呼叫委派 等待委派方法運算完傳回給ANSER
            label5.Text = anser.ToString();//在SHOW給LABEL
        }

上面主要是簡單的來介紹委派的基礎功能
再來還有稍微進階一點的介紹
使用起來更順手

在隨著版本提升委派的宣告方式也越來越精簡
還有一種叫做匿名方式
請看下面CODING!

private void button7_Click(object sender, EventArgs e)
        {
            string ttttttt="";//存放答案用
            var TR1 = new TTO(GGGG);//傳統的建立方式 var則是取代TTO的物件
            //var得出現主要是來解決LINQ的問題個多請查略網路
            TTO TR2 = GGGG;//直接指定類別更直覺!
            TTO TR3 = delegate(string R) { return "MYNAME2:" + R; };//2.0新增的匿名方式
            //直接在delegate中建立類別
            TTO TR4 = N => "myNAME3:" + N;//利用Lambda更精簡了
            //之後讀取 輸出
            ttttttt += TR1("HI1") + "\n";//答案= MYNAME:HI1
            ttttttt += TR2("HI2") + "\n";//答案= MYNAME:HI2
            ttttttt += TR3("HI3") + "\n";//答案= MYNAME2:HI3
            ttttttt += TR4("HI4");//答案= myNAME:HI4
            MessageBox.Show(ttttttt);
            MessageBox.Show(TR1.Invoke("G"));//答案= MYNAME:G
            ////g0.Invoke(); 來引發,另一種是更為直覺的 g1(); 直接執行。
            MessageBox.Show(TR1("R"));//答案= MYNAME:R
        }

再來記錄更進階委派用法
利用累加+=來一個一個執行
比如我觸發事件後 可以同時 做動許多事情
來看一下範例 如下

private void button8_Click(object sender, EventArgs e)
        {
            var g0 = new B(printName);
            //第一次執行
            //g0先將參數傳入printName(s=,A print2Console)
            //然後p是委派物件到print2Console
            //在printName再次委派  p帶入摻數p(s=)
            // 而print2Console執行 s=+773
            // MESSAGESHOW出  S=733
            g0 += delegate(string n, A p) { p("OK:" + n); };
            //第二次執行 匿名法
            //一樣用P再次委派並帶入摻數+"ok"字串
            //p("ok:"+s=) 而p摻數是一個 ptint2Console
            //p("ok:"+s=) 傳入ptint2Console
            //將SHOW出  ok:s=733
            g0 += (n, p) => p("PP" + n);
            //第三次委派利用Lambda
            //一樣 再呼叫 ptint2Console之前
            //n多加一個PP字串,一並傳入ptint2Console
            //將SHOW出 PPs=773
            g0("s=", ptint2Console);//設定參數,注意ptint2Console指定給委派的方法
        }
        public delegate void A(string txt);
        public delegate void B(string n, A p);
        public void printName(string name, A p)
        {
            p(name);//p是ptint2Console
            //而name將傳入ptint2Console+733
        }
        public static void ptint2Console(string txt)
        {
            MessageBox.Show(txt + "773");
        }



在多程序中呼叫委派
在程序中可以呼叫外部程序

private void button9_Click(object sender, EventArgs e)
        {//建立多程序 並在程序START中呼叫委派
            Thread NewThread = new Thread(new ThreadStart(NewThreadMethod));
            NewThread.Start();//開始呼叫NewThreadMethod()
        }
        MyDelegate ShowData = new MyDelegate(Method);//委派指向好Method
        delegate void MyDelegate(int Param);//宣告委派帶摻數
        static void Method(int Param)
        {
            int i = Param;
           
            MessageBox.Show(i.ToString());
            //每2秒SHOW一次
        }
        void NewThreadMethod()
        {
            int i = 0;
            while (true)//無限迴圈運行中
            {//不斷呼叫Method並帶入參數
             this.Invoke(this.ShowData, i);//跨程序關鍵呼叫Method
                Thread.Sleep(2000);
            }
        }

2013年4月18日 星期四

Threading多執行序技術

多執行續可用於
分別各自執行指定的程式區塊
每個程式區塊,將執行完畢後各自輸出結果
而不受干擾
使用命名空間
using System.Threading

出處參考,C#隨性筆記


先來看一下 下面範例

        private void button2_Click(object sender, EventArgs e)
        {    //利用for迴圈來產生5個執行緒
            for (int i = 1; i <= 5; i++)
            {
                //建立執行緒
                //並建立執行緒 subthread
                //執行的目的方法指定為 work
                Thread subThread = new Thread(new ThreadStart(work));
                //這一行特別講解上行結構
                //上面建立Thread物件並委派 縮寫法
                //如果方開建立,則如下
                //先建立ThreadStart 並指定方法work
                //
                //ThreadStart subThreadStart=new ThreadStart(work)
                //在建立Thread
                //
                //Thread subThread=new Thread(subThreadStart);
                subThread.Name = "SubThread" + i.ToString();//設定i=1~5名稱
                subThread.Start();//執行Start方法,Start會呼叫 work
                //分別呼叫5次,這5次分別執行 不收干擾
            }
        }
        static void work()
        {
            //遇到SubThread2延遲15秒
            if (Thread.CurrentThread.Name == "SubThread2")
            {
                Thread.Sleep(15000);//等待15秒
                MessageBox.Show("15秒到了");
            }
            //遇到SubThread1延遲10秒
            else if (Thread.CurrentThread.Name == "SubThread1")
            {
                Thread.Sleep(10000);//等待10秒
                MessageBox.Show("10秒到了");
            }
            MessageBox.Show("Thread State;" + Thread.CurrentThread.ThreadState.ToString());
            MessageBox.Show("目前執行Thread Name:" + Thread.CurrentThread.Name);
            MessageBox.Show("Thread ID:" + Thread.CurrentThread.ManagedThreadId);
        }



上面呼叫SubThread1,SubThread2
將進入IF判斷 如果是 將延遲數秒後才執行
經由程式執行時~
3.4.5將 優先SHOW出
1.2 將晚10秒,15秒SHOW出
可以證明 這兩程序 將各自讀秒 獨立完成個別程式中的程式區塊


如果要帶入參數??
不可以使用ThreadStart
必須使用ParameterizedThreadStart
而副程式中的參數 必須要是 object
再轉換成 各種形式
下面範例將 套入參數部分

private void button3_Click(object sender, EventArgs e)
        {
            for (int I = 1; I <= 5; I++)
            {
                //帶入參數使用ParameterizedThreadStart副程式標籤 必須是object
                Thread GO = new Thread(new ParameterizedThreadStart(TTTT));
                GO.Name = "myname=" + I.ToString();
                GO.Start("No" + I.ToString());////呼叫TTTT並帶入摻數NO1~NO5
            }
        }
        static void TTTT(object R)//只能是object
        {
            string son = (string)R;//再將object轉成要的型態
            if (son == null)
            {
                MessageBox.Show("轉型失敗");//如果再轉型有問題 立即顯示
            }
            if (Thread.CurrentThread.Name == "myname=2")
            {
                Thread.Sleep(10000);//如果是myname=2 讓他等10秒在SHOW出
            }
            MessageBox.Show("傳入的參數R=" + R.ToString());
            MessageBox.Show("Thread.State=" + Thread.CurrentThread.ThreadState.ToString());
            MessageBox.Show("Thread.Name=" + Thread.CurrentThread.Name);
            MessageBox.Show("Thread.ID=" + Thread.CurrentThread.ManagedThreadId);
        }

2013年4月13日 星期六

遞迴基礎概念

說到遞迴真是無法馬上很清晰的明白整個過程
為了預防忘記,下面盡量使用較清晰方式記錄

比如1乘到5 等於 120
也可以寫成5!=120
數學原理如下
1*1=1
1*2=2
2*3=6
6*4=24
24*5=120
那~如何使用遞迴?
下面將使用到 "for 迴圈" 與 "呼叫副程式"
即可達到遞迴效果
先來看一下 簡單的遞迴程式碼

private void button2_Click(object sender, EventArgs e)
        {
            int g, y = 5;//先建立2個整數 一個=5代表終直
            g = SH(y);//g用來放SH(y)副程式,所傳回來的數值
            richTextBox1.Text = "計算結果:"+g + "\n";//將數值顯示出來
        }
        static int SH(int w)//呼叫副程式,這時候w=5
        {
            if (w == 0)//如果w=0回傳1
                return 1;
            else//不然w-1繼續呼叫副程式  一直到 w=0
                return w * SH(w - 1);
        }




 



來看一下
第一次呼叫副程式時w=5
5不等於0時
5-1在呼叫一次
5*sh(5-1)= 5*(戴回傳值)=?

第二次呼叫副程式w=4
4不等於0時
4-1再呼叫一次
4*sh(4-1)= 4*(戴回傳值)=?

第三次呼叫副程式w=3
3不等於0時
3-1再呼叫一次
3*sh(3-1)= 3*(戴回傳值)=?

第四次呼叫副程式w=2
2不等於0時
2-1再呼叫一次
2*sh(2-1)= 2*(戴回傳值)=?

第五次呼叫副程式w=1
1不等於0時
1-1再呼叫一次
1*sh(1-1)= 1*(戴回傳值)=?

第六次呼叫副程式w=0
0=0時 回傳1

之後倒著回傳回去

1*(回傳直1)=1

2*(回傳直1)=2

3*(回傳直2)=6

4*(回傳直6)=24

5*(回傳直24)=120

之後120傳回sh(y)=120
show出答案 120




再來 許多教材中
同時呼叫兩個副程式
來解釋遞迴概念

第一次接觸一定會花不少時間去思考
程式的步驟
下面將使用到 利用遞迴來判斷費式數列(Fibonacci)
誰知道啥事費式阿@@

必須先明白費式數列(Fibonacci)的意思才能明白程式的原理
對於數學不太好的我紀錄如下
來看一組 數字碼 如下
1、1、2、3、5、8、13、21、34、55、89
就像許多測試IQ的考古題 一時難以辨識這是啥?
試著嘗試 在字碼中找到規律?
下面講解 數字碼中的規律!!

費式數列中數列的前兩項為 1、1
在1 , 1 後面等數 等於 1+1=2
下一個數字則是
1+2=3
再來則是
2+3=5
以此類推~
就能明白 數字中的規律
公式是
Fn=(Fn-1)+(Fn-2)

題外話 值得一提
而黃金比例剛好是
Fn/Fn-1 =0.618或1.618
為何叫黃金比例
許多的生物構成都和斐波那契數列有正相關。例如人體腳底至頭頂之距離和從肚臍至腳底之距趨近\lim_{n \to \infty}\frac{F_n}{F_{(n-1)}} ,向日葵種子螺旋排列99%F_n



再來!
來看看如何使用第迴來計算費式數列
假如想知道 第幾幾階 有幾個節點


來看下面程式碼

private void btn_Get_Click(object sender, EventArgs e)
        {
            int P_int_temp;//定義整型變數
            //利用TryParse判斷有無輸入數值
            if (int.TryParse(txt_value.Text, out P_int_temp))
            {
                lb_result.Text = "結果為:" + Get(P_int_temp).ToString();
            }
            else
            {
                MessageBox.Show(//提示輸入正確數值
                    "請輸入正確的數值!", "提示!");
            }
        }
        /// <summary>
        /// 遞迴算法
        /// </summary>
        /// <param name="i">參與計算的數值</param>
        /// <returns>計算結果</returns>
        int Get(int i)
        {
            if (i <= 0)       //判斷數值是否小於0
                return 0;      //返回數值0
            else if (i >= 0 && i <= 2)   //判斷位數是否大於等於0並且小於等於2
                return 1;      //返回數值1
            else        //如果不滿足上述條件執行下面語句
                return Get(i - 1)+Get(i-2); //返回指定位數前兩位數的和
        }

要解釋程式執行過程需要深度的思考
有一點複雜還需要一點想像力!

假設 輸入4
Get(P_int_temp)等待傳回數值

第一次進入副程式
4有小於0嗎? 沒有
4有大於等於0 而且 小於等於2嗎?  沒有
再次呼叫2個副程式 分別是
get(4-1)+get(4-2),注意:將執行第二次副程式get(4-1) 而get(4-2)待命

第二次進入程式
4-1=3
3有小於0嗎? 沒有
3有大於等於0 而且 小於等於2嗎? 沒有
再次呼叫2個副程式 分別是
get(3-1)+get(3-2),注意:將執行第三次副程式get(3-1) 而get(3-2)待命

第三次進入復程式
3-1=2
2有小於0嗎? 沒有
2有大於等於0 而且 小於等於2嗎?  有
回傳get(3-1)數值1

注意
回到第二副程式
get(3-1)已傳回數值=1
開始執行剛才待命的Get(3-2)

第四次呼叫副程式
3-2=1
1有小於0嗎? 沒有
1有大於等於0 而且 小於等於2嗎? 有
回傳get(3-2)數值1

再次注意
第二副程式呼叫的兩個副程式
也傳回數值1
所以 在第二副程式中
get(1)+get(1) = 2
副程式2 已經算好了
數值2將 傳回
第一副程式

第一副程式中
get(4-1) 已收到傳回職2
get(2)+get(4-2)=?
開始執行待命的get(4-2)
 

get(4-2)將進入第五次呼叫副程式
4-2=2
2有小於0嗎? 沒有
2有大於等於0 而且 小於等於2嗎? 有
回傳get(3-1)數值1

回到第一次呼叫的副程式

get(傳回數值:2)+get(傳回數值:1)=3

Get(P_int_temp)等待傳回數值=3

答案=3

數字越大  越複雜 只需明白 程式運作順序即可如法炮製
在使用 遞迴 須注意到!!  型別大小
超出是會溢出的

2013年4月12日 星期五

無限的for迴圈與Console簡單介紹

下面code+註解
class program
{
    static void Main()
    {
        System.Console.Title = "迴圈向控制台中輸入內容";//定義控制台標題
        System.Console.WindowWidth = 30;//設定控制台視窗寬度
        System.Console.WindowHeight = 2;//設定控制台視窗高度
        for (; ; )//開始無限迴圈
        {
            System.Console.WriteLine("目前系統時間是:{0}",//輸出系統目前時間
                System.DateTime.Now.ToString("dd日 hh:mm:ss"));
            //在ToString可以格式化顯示方式
            System.Threading.Thread.Sleep(1000);//每一秒更新一次畫面
            System.Console.Clear();//清空控制台訊息,如果沒清除,程序將持續印出時間
        }
    }
}

2013年4月11日 星期四

combobox搭配switch用this.backcolor控制顏色,與Timer簡單介紹

在視窗範例中無BUTTON觸發紐
可以使用Events觸發事件
在屬性視窗中"閃電圖紐"可選擇觸發事件
我們選擇SelectedIndexChanged
預設名也如同標題叫SelectedIndexChanged
先來看一下範例
private void cbox_select_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (cbox_select.SelectedIndex)//使用switch判斷視窗使用哪種顏色
            {
                case 0:
                    this.BackColor = Color.Red;//視窗設定為紅色
                    break;
                case 1:
                    this.BackColor = Color.Green;//視窗設定為綠色
                    break;
                case 2:
                    this.BackColor = Color.Blue;//視窗設定為藍色
                    break;
            }
        }



關於事件!需要注意的是?
如果我再新增一個combobox控制向時
同樣觸發事件使用SelectedIndexChanged
但是事件名如果一樣使用預設的"SelectedIndexChanged"
在程式部分,觸發的區塊會是同一個地方
所以必須修改觸發名稱 比如+一個1來區別
例如下面
private void cbox_select_SelectedIndexChanged1(object sender, EventArgs e)
        {//此事件觸發名稱為SelectedIndexChanged1
        }



再來利用TIMER來控制顏色

拖出TIMER
Enable=true
interval=3000 三秒
觸發事件是Tick
在tick中寫入控制顏色範例如下

private void timer1_Tick(object sender, EventArgs e)
        {
            this.BackColor = Color.Black;
        }

可多項判斷的switch case: break; default:

利用下拉式選擇幾月份
switch帶入條件
case做季節判斷 並SHOW出訊息
直到break跳出程式區塊
default則是例外處理
來看下面範例

private void btn_true_Click(object sender, EventArgs e)
        {
            switch (cbox_select.SelectedIndex + 1)//Selectedindex由0開始所以+1
            {
                case 3://如果是3.4.5月
                case 4:
                case 5:
                    MessageBox.Show("春季", "提示!");
                    break;//跳出程式區塊
                case 6://如果是6.7.8月
                case 7:
                case 8:
                    MessageBox.Show("夏季", "提示!");
                    break;
                case 9:
                case 10:
                case 11:
                    MessageBox.Show("秋季", "提示!");
                    break;
                case 12:
                case 1:
                case 2:
                    MessageBox.Show("冬季", "提示!");
                    break;
                default://如果沒有選擇月份彈出提示訊息
                    MessageBox.Show("請選擇月份", "提示!");
                    break;
            }
        }


不只可以做數值判斷 也可以做 字串與布林的判斷

下面範例為 判斷 True與Flase


private void button1_Click(object sender, EventArgs e)
        {
            switch (radioButton1.Checked)
            {
                case true:
                    MessageBox.Show("true");
                    break;
                case false:
                    MessageBox.Show("false");
                    break;
            }
        }




再來是字串上的判斷範例如下


 private void button2_Click(object sender, EventArgs e)
        {
            switch (comboBox1.SelectedItem.ToString())
            {
                case "左楠":
                    MessageBox.Show("加油站");
                    break;
                case "NXP":
                    MessageBox.Show("半導體");
                    break;
                case "請選擇公司名稱":
                    MessageBox.Show("請點選下拉式清點選擇");
                    break;
            }
        }




上面程式碼在執行過程中 出了一點問題

來記錄一下在製作範例過程遇到的問題與排除方式
原因如下:
發現如果使用者,選空白選項時
不能使用default來使用例外處裡,原因是
在selectedindex為null值時,無法做ToString轉換
下面稍微研究 整理出幾套方法

本來想在combobox.Text直接輸入"請選擇"
結果不行? 因為
設定combobox的DropDownStyle是DropDownList
時不能對Text修改 改了按下ENTER之後一樣空白
後來才知道 要在ITEM加入"請選擇"
直接指定TEXT才可以
下面紀錄設定DropDownList又可以避免null的方法



第一招,直接在Item中新增一個"請選擇"
並且在 程式開啟時
設定combobox的text值為combobox.Item[0].ToString()
讓combobox保持在第一項新增的"請選擇"項目

下面範例同上,下面只是加入設定,combobox.text

private void Frm_Main_Load(object sender, EventArgs e)
{//item[0]以字串指定給text程式開啟瞬間已經設定好
  comboBox1.Text = comboBox1.Items[0].ToString();
}



@@再來查略一下控制項屬性
發現到一個更簡單的方法
可讓defalut發揮作用
紀錄如下

private void button2_Click(object sender, EventArgs e)
        {
            switch (comboBox1.Text)//直接判斷text就好
            {
                case "左楠":
                    MessageBox.Show("加油站");
                    break;
                case "NXP":
                    MessageBox.Show("半導體");
                    break;
                default:
                    MessageBox.Show("請選擇");
                    break;
            }
        }

2013年4月9日 星期二

combobox識別身分範例與item導入物件概念

下面簡單介紹combox中的基礎應用
在item屬性中分別 加入admin與user
在使用IF ELSE進行判斷用戶
下面範例

        private void btn_login_Click(object sender, EventArgs e)
        {
            //下面判斷如果選擇是一個叫"admin"的話true
            if (cbox_select.SelectedItem.ToString() == "admin")
            {
                MessageBox.Show(//如果是admin登陸則提示管理員登陸
                    "管理員登入", "提示!");
            }
            else//如果不是false
            {
                MessageBox.Show(//如果是user登陸則提示普通用戶登陸
                    "普通用戶登入", "提示!");
            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            cbox_select.SelectedIndex = 0;//默認選擇combobox中的第一項
        }

防止用戶誤觸修改combobox中的內容,可設定DropDownStyle屬性中的DropDownList即可


由於顯示一般是字串物件,但item.add方法 可接受物件
而下拉式清單會呼叫item中每一個objecy中的字串方法
並顯示在combobox中
所以可以利用此特性 建立類別 再利用add加入新物件
下面修改後的範例

public partial class Frm_Main : Form
    {
        class ttest
        {
            //因為Items集合中的add方法接受"物件"
            //
            //用override重新定義ToString()
            //item會呼叫物件中的ToString()方法
            //而ToStrung()是一個方法
            //但是一旦執行ttest 遇到override ToString()就必須重新定義
            //利用OVERRIDE複寫基底的TOSTRING
            //當呼叫ttest類別時 呼叫字串 override會複寫ToString
            //而tostring 回傳一個字串"程式設計"給 Add
            public override string ToString()
            {
                return "程式設計";//建立字串方法 傳回"程式設計"
            }
        }
        public Frm_Main()
        {
            InitializeComponent();
        }
        private void btn_login_Click(object sender, EventArgs e)
        {
            //下面判斷如果選擇是一個叫"admin"的話true
            if (cbox_select.SelectedItem.ToString() == "admin")
            {
                MessageBox.Show(//如果是admin登陸則提示管理員登陸
                    "管理員登入", "提示!");
            }
            else//如果不是false
            {
                MessageBox.Show(//如果是user登陸則提示普通用戶登陸
                    "普通用戶登入", "提示!");
            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            //ttest objectName = new ttest();
            //or
            //直接new
            cbox_select.Items.Add(new ttest());//加入新物件 
            cbox_select.SelectedIndex = 0;//默認選擇combobox中的第一項
        }

簡潔的使用if eles或?:做邏輯判斷

雖然是常使用的if else判斷式 不過複習到這裡就在寫一篇 當作幫助記憶

簡單的利用if else 就好略讀 也可以做 窩狀複合式判斷 較複雜不提!
基本概念範例就可如法炮製 看下面

private void btn_go_Click(object sender, EventArgs e)
        {
            if (rbtn_school.Checked)//判斷小明去學校還是去醫院
            {
                MessageBox.Show("向左走", "提示!");//如果去學校則向左走
            }
            else
            {
                MessageBox.Show("向右走", "提示!");//如果去醫院則向右走
            }
        }



可使用三元運算使得程式更簡潔
請看下面

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show(rbtn_school.Checked ? "走左邊" : "走右邊","我是標題");
        }




三元運算 一行搞定@@不過很少使用 不太熟悉 要來研究一下
if else較彈性也可搭配複合邏輯判斷與渦狀 比較熟悉

2013年4月8日 星期一

使用as來轉換

下面簡單列子 示範利用簡單的as將object轉換指定型態


private void button1_Click(object sender, EventArgs e)
        {
            string Q = "TEST";//建立一個字串
            object W = Q;//字串轉物件
            string A = W as string;//物件轉回字串 判斷是否成功
            if (A != null)//A不等於null
            {
                MessageBox.Show("OK");//成功 show出ok
            }
            else//A等於null
                MessageBox.Show("不OK");
        }




再來,來看個轉型不成功null的例子
private void button1_Click(object sender, EventArgs e)
        {
            int Q=1;
            object W = Q;
            string A = W as string;
            if (A != null)
            {
                MessageBox.Show("OK");
            }
            else
                MessageBox.Show("不OK");//在判斷時無法成功轉型因此A還是NULL
        }

嘗試轉成型別int 或 double 數值型態valueType
結果發現 編譯器SHOW出(int is a non-nullable value type)
才驚覺發現 原來有使用上的限制
原因是轉換過程是if做null判斷
所以不可以使用valueType數值類型 比如說 int double 之類的
不然連執行都不能執行 編譯將會出現錯誤

下面示範 連執行都不能執行的 列子

private void button1_Click(object sender, EventArgs e)
        {
            int Q=1;
            object W = Q;
            int A = W as int;
            if (A != null)
            {
                MessageBox.Show("OK");
            }
            else
                MessageBox.Show("不OK");
        }

2013年4月6日 星期六

使用is關鍵字判斷物件是否與指定類型一樣

程式開發過程,因型態時常的轉換 或 轉換不成功 ,出現異常增加不穩定性
使用 is 關鍵字 可以判斷 是否與指定類型相同?  相容true 不相容false

下面簡單的概念

private void button1_Click(object sender, EventArgs e)
        {
            string PP = "程式設計";//建立字串型態
            object OBJ = PP;//將字串轉物件
            if (OBJ is string)//查詢OBJ是不是STRING
            {
                MessageBox.Show("OBJ 是一個strin型態");
            }
            else
            {
                MessageBox.Show("不是string型態");
            }
        }


在看以下範例


  private void btn_Get_Click(object sender, EventArgs e)
        {
            //下面是radiobutton 裡用?:三元運算做判斷 true 是字串 false 是檔案型態
            //面板上有 radiobutton1 與2
            object P_obj = rbtn_target1.Checked ?
                (object)"C# 編程詞典" : new System.IO.FileInfo(@"d:\");
            if (rbtn_class1.Checked)//判斷選擇了哪一個類型
            {
                if (P_obj is System.String)//判斷物件是否為字符串類型
                    MessageBox.Show(//提示相容訊息
                        "物件與指定類型相容", "提示!");
                else
                    MessageBox.Show(//提示不相容訊息
                        "物件與指定類型不相容", "提示!");
            }
            else
            {
                if (P_obj is System.IO.FileInfo)//判斷物件是否為文件類型
                    MessageBox.Show(//提示相容訊息
                        "物件與指定類型相容", "提示!");
                else
                    MessageBox.Show(//提示不相容訊息
                        "物件與指定類型不相容", "提示!");
            }
        }

2013年4月3日 星期三

資源回收方法與基礎

前篇 理解記憶體配置之後 可以開始記錄如何有效管理記憶體的配置

建立類別 與 解構

先建立類別 利用~來解構類別 並SHOW出訊息告知已解構
class Father
        {
            public Father()
            {
                MessageBox.Show("類別狀態:建構 Father");
            }
            ~Father()
            {
                MessageBox.Show("類別狀態:解構 Father");
            }
        }
       
        class Son : Father
        {
            public Son()
            {
                MessageBox.Show("類別狀態:建構 Son");
            }
            ~Son()
            {
                MessageBox.Show("類別狀態:解構 Son");
            }
        }




再來 來試試看 執行的步驟 建立BUTTON
private void button1_Click(object sender, EventArgs e)
        {
            richTextBox1.Text = "程式開始" + "\n"; ;
            Son me = new Son();
            me = null;
            richTextBox1.Text += "程式結束" + "\n";
            //直到程式被關閉 才會執行解構
        }



執行 先後順序 如下
程式開始
建構FATER
建構SON
程式結束
會發現程式 尚未解構 
直到把程式關閉 才SHOW出 解構訊息
因為使用~來解構 會呼叫Object.Finalize方法
而Finalize只是 允許物件在記憶體回收進行回收之前,嘗試釋放資源並執行其他清除作業。

下面列子中 與上一樣 不同與加入 GC強迫回收!
PS:使用 同上一樣的類別
private void button2_Click(object sender, EventArgs e)
        {
            richTextBox1.Text = "程式開始" + "\n";
            Son me = new Son();
            me = null;
            richTextBox1.Text += "開始執行強迫回收"+"\n";
            //以GC指令強迫.Net framework資源回收
            GC.Collect();
            //並使用WaitForPendingFinalizers method等到確實回收後
            //再繼續執行,因為資源回收時是在另一個thread之故。
            GC.WaitForPendingFinalizers();
            richTextBox1.Text += "程式結束" + "\n";
        }

執行順序為
程式開始
建構FATER
建構SON
解構SON
解構FATER
程式結束

可以程式尚未結束 先進行回收




再來可以使用IDisposable介面
類別程式碼如下
class FFather : IDisposable //父類別直接指向IDisposable
        {
            public FFather()
            {
                MessageBox.Show("類別狀態:建構 FFather");
            }
            public void Dispose()
            {
                MessageBox.Show("類別狀態:解構 FFather");
            }
        }
        class SSon : FFather, IDisposable
        {
            public SSon()
            {
                MessageBox.Show("類別狀態建構 SSon");
            }
            new public void Dispose()
            {
                MessageBox.Show("類別狀態解構 SSon");
            }
        }




一樣寫個BUTTON來看執行順序

private void button3_Click(object sender, EventArgs e)
        {
            richTextBox1.Text = ("程式開始");
            using (SSon me = new SSon())
            {
                richTextBox1.Text += ("程式執行中");
            }
            richTextBox1.Text += ("程式結束");
            //只有呼叫子類別的回收
        }



執行順序如下
程式開始
建構FFATHER
建構SSON
解構SSON
程式結束

PS:一定會覺得奇怪 FFATHER怎沒被解構?

Net framework只呼叫子類別的Dispose method 卻沒有呼叫父類別的Dispose method,所以,實作IDisposable介面時,父類別的資源回收要由子類別呼叫

請看下面 類別改寫 加入base.Dispose()


class FFFather : IDisposable //父類別直接指向IDisposable
        {
            public FFFather()
            {
                MessageBox.Show("類別狀態:建構 FFFather");
            }
            public void Dispose()
            {
                MessageBox.Show("類別狀態:解構 FFFather");
            }
        }
        class SSSon : FFFather, IDisposable
        {
            public SSSon()
            {
                MessageBox.Show("類別狀態建構 SSSon");
            }
            new public void Dispose()
            {
                MessageBox.Show("類別狀態解構 SSSon");
                base.Dispose();
            }
        }


執行順序如下
程式開始
建構FFFATHER
建構SSSON
解構SSSON
解構FFFATHER
程式結束


注意使用  IDisposable介面時候
建立物件時 務必使用 using
如果不使用using IDisposable將毫無作用


資源釋放觀念整理 與 回收方法實作與Box Unbox

 
 
寫C#程式也有一段時間了,算一算現在寫的這個程式已是第四個用C#寫的較有規模的程式。一直以來因為懶惰和玩不完的電動,都沒有好好去研究C#中資源釋放的問題,尤其後來這三次寫的程式都需要用到以C++寫成的Library(以C++/CLI寫一個Wrapper Class來包裝),有二次要用到Managed DirectX,對於各種資源的管理更顯得重要。所以這一次就稍微認真了點,去搜尋了一下C#資源釋放的相關文章來做個統整。

剛接觸C#沒多久的人,通常對於GC(Garbage Collector)都會跟我有一樣的茫然,「GC什麼時候會回收資源?」、「哪些東西會被GC回收?」、「太倚賴GC是不是會造成程式效率低落?」,以下就從基礎開始談起GC的運作機制。