亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入理解C#中常見(jiàn)的委托

 更新時(shí)間:2013年06月09日 09:38:08   作者:  
本篇文章是對(duì)C#中常見(jiàn)的委托進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下

一提到委托,浮現(xiàn)在我們腦海中的大概是聽(tīng)的最多的就是類(lèi)似C++的函數(shù)指針吧,呵呵,至少我的第一個(gè)反應(yīng)是這樣的。
關(guān)于委托的定義和使用,已經(jīng)有諸多的人講解過(guò),并且講解細(xì)致入微。我就不用多廢話(huà)了。
今天我要說(shuō)的是C#中的三種委托方式:Func委托,Action委托,Predicate委托以及這三種委托的常見(jiàn)使用場(chǎng)景。
Func,Action,Predicate全面解析
首先來(lái)說(shuō)明Func委托,通過(guò)MSDN我們可以了解到,F(xiàn)unc委托有如下的5種類(lèi)型:

復(fù)制代碼 代碼如下:

(1) *delegate TResult Func<TResult>();
(2)*delegate TResult Func<T1,TResult>(T1 arg1);
(3) *delegate TResult Func<T1,T2,TResult>(T1 arg1, T2 arg2);
(4)*delegate TResult Func<T1,T2,T3,TResult>(T1 arg1, T2 arg2, T3 arg3);
(5)*delegate TResult Func<T1,T2,T3,T4,TResult>T1 arg1, T2 arg2, T3 arg3, T4 arg4);

其中(1)只能委托無(wú)參但是有返回值的函數(shù),TResult就是其返回類(lèi)型。
而(2)只能委托具有一個(gè)傳入?yún)?shù),有返回值的函數(shù),T1為一個(gè)傳入?yún)?shù),TResult為返回類(lèi)型。
(3)只能委托具有二個(gè)傳入?yún)?shù),有返回值的函數(shù),T1和T2為兩個(gè)傳入?yún)?shù),TResult為返回類(lèi)型,(4)和(5)以此類(lèi)推。
那么如何來(lái)使用呢? 下面給出一個(gè)簡(jiǎn)單的幾個(gè)例子:
復(fù)制代碼 代碼如下:

#region Func委托

///Func<TResult>的用法
///這里TResult代表函數(shù)的返回值類(lèi)型
///只能代理返回值為T(mén)Result類(lèi)型的無(wú)參函數(shù)
Func<string> func = delegate()
{
    return "我是Func<TResult>委托出來(lái)的結(jié)果";
};
Console.WriteLine(func());
Console.ReadKey();
///Func<T,TResult>的用法
///這里的T為代理的函數(shù)的傳入類(lèi)型,TResult代表函數(shù)的返回值類(lèi)型
///只能代理參數(shù)為T(mén)類(lèi)型,返回值為T(mén)Result類(lèi)型的函數(shù)
Func<string, string> funcOne = delegate(string s)
{
    return s.ToUpper();
};
Console.WriteLine(funcOne("我是Func<T,TResult>委托出來(lái)的結(jié)果"));
Console.ReadKey();
///Func<T1,T2,TResult>的用法
///這里T1,T2為代理的函數(shù)的傳入類(lèi)型,TResult代表函數(shù)的返回值類(lèi)型
///只能代理參數(shù)為T(mén)1,T2類(lèi)型,返回值為T(mén)Result類(lèi)型的函數(shù)
Func<string, string, string> funcTwo = delegate(string value1, string value2)
{
    return value1 + " " + value2;
};
Console.WriteLine(funcTwo("我是", "Func<T1,T2,TResult>委托出來(lái)的結(jié)果"));
Console.ReadKey();
#endregion


上面代碼中,我用了匿名方法來(lái)代替函數(shù),其中delegate()代表無(wú)參函數(shù),delegate(string s)代表有一個(gè)傳入?yún)?shù)的函數(shù),以下的以此類(lèi)推。

然后需要說(shuō)明的就是Action委托,這個(gè)委托也是非常常用的,尤其是在涉及到線(xiàn)程和界面交互的時(shí)候,配合著lamada表達(dá)式使用,非常方便的實(shí)現(xiàn)二者的交互。后面我會(huì)提到用法。
來(lái)看看Action委托的幾種表現(xiàn)形式:
復(fù)制代碼 代碼如下:

(1) * delegate void Action(); 無(wú)參,無(wú)返回值
(2)* delegate void Action<T>(T1 arg1);
(3)* delegate void Action<T1,T2>(T1 arg1, T2 arg2);
(4)* delegate void Action<T1,T2,T3>T1 arg1, T2 arg2, T3 arg3);
(5)* delegate void Action<T1,T2,T3,T4>T1 arg1, T2 arg2, T3 arg3, T4 arg4);

從上面可以看出,總共有5中表現(xiàn)形式,其中(1)既沒(méi)有傳入?yún)?shù),也沒(méi)有返回值,那么它適合代理那些無(wú)參,無(wú)返回值的函數(shù);(2)有一個(gè)傳入?yún)?shù),無(wú)返回值,適合代理有參,無(wú)返回值的函數(shù),(3)(4)(5)以此類(lèi)推。最都容納四個(gè)傳入?yún)?shù)。
那么如何使用呢?下面有一些簡(jiǎn)單的例子:
復(fù)制代碼 代碼如下:

#region Action的用法
///Action<T>的用法
///這里的T為代理函數(shù)的傳入類(lèi)型,無(wú)返回值
Action<string[]> action = delegate(string[] x)
{
    var result = from p in x
     where p.Contains("s")
     select p;
    foreach (string s in result.ToList())
    {
        Console.WriteLine(s);
    }
};
string[] str={ "charlies","nancy","alex","jimmy","selina"};
action(str);
Console.ReadKey();
#endregion

上面的例子是通過(guò)傳入的String類(lèi)型的數(shù)組,找出其中包含有字符s的項(xiàng),然后輸出到控制臺(tái)。
最后一個(gè)就是Predicate委托,這個(gè)的形式比較少一些,就是一個(gè)傳入?yún)?shù),返回值為bool類(lèi)型,具體示例如下:
復(fù)制代碼 代碼如下:

#region Predicate
          ///bool Predicate<T>的用法
///輸入一個(gè)T類(lèi)型的參數(shù),返回值為bool類(lèi)型
Predicate<string[]> predicate = delegate(string[] x)
{
    var result = from p in x
     where p.Contains("s")
     select p;
    if (result.ToList().Count > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
};
string[] _value = { "charlies", "nancy", "alex", "jimmy", "selina" };
if (predicate(_value))
{
    Console.WriteLine("They contain.");
}
else
{
    Console.WriteLine("They don't contain.");
}
Console.ReadKey();
#endregion

上面的代碼其實(shí)也是判斷String數(shù)組中有沒(méi)有包含s的項(xiàng),有的話(huà)就在控制臺(tái)打印出  They contain.沒(méi)有的話(huà)就打印出They don't contain.
總結(jié)一下這三個(gè)的特點(diǎn)就是:
復(fù)制代碼 代碼如下:

Func可以接受0個(gè)至4個(gè)傳入?yún)?shù),必須具有返回值
Action可以接受0個(gè)至4個(gè)傳入?yún)?shù),無(wú)返回值
Predicate只能接受一個(gè)傳入?yún)?shù),返回值為bool類(lèi)型

下面附上全部實(shí)現(xiàn)代碼:
復(fù)制代碼 代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegateIntegrateConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
#region Func委托

///Func<TResult>的用法
///這里TResult代表函數(shù)的返回值類(lèi)型
///只能代理返回值為T(mén)Result類(lèi)型的無(wú)參函數(shù)
Func<string> func = delegate()
{
    return "我是Func<TResult>委托出來(lái)的結(jié)果";
};
Console.WriteLine(func());
Console.ReadKey();
///Func<T,TResult>的用法
///這里的T為代理的函數(shù)的傳入類(lèi)型,TResult代表函數(shù)的返回值類(lèi)型
///只能代理參數(shù)為T(mén)類(lèi)型,返回值為T(mén)Result類(lèi)型的函數(shù)
Func<string, string> funcOne = delegate(string s)
{
    return s.ToUpper();
};
Console.WriteLine(funcOne("我是Func<T,TResult>委托出來(lái)的結(jié)果"));
Console.ReadKey();
///Func<T1,T2,TResult>的用法
///這里T1,T2為代理的函數(shù)的傳入類(lèi)型,TResult代表函數(shù)的返回值類(lèi)型
///只能代理參數(shù)為T(mén)1,T2類(lèi)型,返回值為T(mén)Result類(lèi)型的函數(shù)
Func<string, string, string> funcTwo = delegate(string value1, string value2)
{
    return value1 + " " + value2;
};
Console.WriteLine(funcTwo("我是", "Func<T1,T2,TResult>委托出來(lái)的結(jié)果"));
Console.ReadKey();
/*************余下的類(lèi)似上面的這種操作,最多可以接受四個(gè)傳入?yún)?shù)***************
 *delegate TResult Func<TResult>(); 
 *delegate TResult Func<T1,TResult>(T1 arg1);
 *delegate TResult Func<T1,T2,TResult>(T1 arg1, T2 arg2);
 *delegate TResult Func<T1,T2,T3,TResult>(T1 arg1, T2 arg2, T3 arg3);
 *delegate TResult Func<T1,T2,T3,T4,TResult>T1 arg1, T2 arg2, T3 arg3, T4 arg4);
 */
#endregion
#region Action的用法
///Action<T>的用法
///這里的T為代理函數(shù)的傳入類(lèi)型,無(wú)返回值
Action<string[]> action = delegate(string[] x)
{
    var result = from p in x
     where p.Contains("s")
     select p;
    foreach (string s in result.ToList())
    {
        Console.WriteLine(s);
    }
};
string[] str={ "charlies","nancy","alex","jimmy","selina"};
action(str);
Console.ReadKey();
/***************余下的類(lèi)似上面的這種操作,最多可以接受四個(gè)傳入?yún)?shù)**********
 * delegate void Action(); 無(wú)參,無(wú)返回值
 * delegate void Action<T>(T1 arg1);
 * delegate void Action<T1,T2>(T1 arg1, T2 arg2);
 * delegate void Action<T1,T2,T3>T1 arg1, T2 arg2, T3 arg3);
 * delegate void Action<T1,T2,T3,T4>T1 arg1, T2 arg2, T3 arg3, T4 arg4);
 */
#endregion
#region Predicate
///bool Predicate<T>的用法
///輸入一個(gè)T類(lèi)型的參數(shù),返回值為bool類(lèi)型
Predicate<string[]> predicate = delegate(string[] x)
{
    var result = from p in x
     where p.Contains("s")
     select p;
    if (result.ToList().Count > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
};
string[] _value = { "charlies", "nancy", "alex", "jimmy", "selina" };
if (predicate(_value))
{
    Console.WriteLine("They contain.");
}
else
{
    Console.WriteLine("They don't contain.");
}
Console.ReadKey();
#endregion
        }
    }
}


下面這部分主要講解如何在WinForm中利用這些委托進(jìn)行線(xiàn)程和界面的交互。
首先對(duì)于Func來(lái)說(shuō),由于其必須具有返回值,所以我們可以利用如下代碼來(lái)實(shí)現(xiàn)線(xiàn)程和界面的交互:
復(fù)制代碼 代碼如下:

#region 利用Func實(shí)現(xiàn)線(xiàn)程和界面交互
        private void AlternationUsingFunc(object text)
        {
//無(wú)參數(shù),但是返回值為bool類(lèi)型
this.Invoke(new Func<bool>(delegate()
{
    button1.Text = text.ToString();
    return true; //返回值
}));
        }
        private void AlternationUsingFuncThread()
        {
WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingFunc);
ThreadPool.QueueUserWorkItem(waitCallBack, "Func的使用");
        }
        private void button1_Click(object sender, EventArgs e)
        {
AlternationUsingFuncThread();
        }
        #endregion

其中
復(fù)制代碼 代碼如下:

this.Invoke(new Func<bool>(delegate()
{
    button1.Text = text.ToString();
    return true; //返回值
}));

這段代碼中利用了Func<TResult>這種類(lèi)型,也就是沒(méi)有傳入?yún)?shù),但是有一個(gè)bool類(lèi)型的返回值,然后將這個(gè)函數(shù)利用加入到線(xiàn)程池中,最后運(yùn)行,這里我們成功的設(shè)置了button1的text為“Func的使用”。
然后,對(duì)于Action來(lái)說(shuō),由于其可以無(wú)參,無(wú)返回值,那么它的交互方式最為簡(jiǎn)便,同時(shí)也是使用最多的,先看有參的調(diào)用方式:
復(fù)制代碼 代碼如下:

#region 利用Action實(shí)現(xiàn)線(xiàn)程和界面交互
        private void AlternationUsingAction(object text)
        {
//需要一個(gè)T類(lèi)型的參數(shù),無(wú)返回值
this.Invoke(new Action<object>(delegate(object myText)
{
    myText = text;
    button2.Text = text.ToString();
}),text);
        }
        private void AlternationUsingActionThread()
        {
WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingAction);
ThreadPool.QueueUserWorkItem(waitCallBack,"Action的使用");
        }
        private void button2_Click(object sender, EventArgs e)
        {
AlternationUsingActionThread();
        }
        #endregion

在上面的代碼示例中,我們使用了帶有一個(gè)傳入?yún)?shù)的Action委托,當(dāng)然了,匿名類(lèi)型delegate(object myText)匿名代理了具有一個(gè)傳入?yún)?shù)的函數(shù)。
其實(shí)簡(jiǎn)單點(diǎn)來(lái)說(shuō),可以像如下方式使用:
復(fù)制代碼 代碼如下:

this.Invoke((Action)(()=>
{
    button2.Text = text.ToString();
}));

這樣就顯得非常的方便。
最后一個(gè)當(dāng)然是Predicate委托,和上面類(lèi)似,只是寫(xiě)起來(lái)麻煩一些,它需要一個(gè)傳入?yún)?shù),并且返回一個(gè)bool類(lèi)型:
復(fù)制代碼 代碼如下:

#region 利用Predicate實(shí)現(xiàn)線(xiàn)程和界面的交互
        private void AlternationUsingPrecidate(object text)
        {
//需要一個(gè)T類(lèi)型的參數(shù),返回bool類(lèi)型
this.Invoke(new Predicate<object>(delegate(object myText) 
{
    myText = text;
    button3.Text = myText.ToString();
    return true;   //返回值
}),text);
        }
        private void AlternationUsingPrecidateThread()
        {
WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingPrecidate);
ThreadPool.QueueUserWorkItem(waitCallBack,"Predicate的使用");
        }
        private void button3_Click(object sender, EventArgs e)
        {
AlternationUsingPrecidateThread();
        }
        #endregion

具體的注釋我已經(jīng)寫(xiě)在代碼中了,最后運(yùn)行,能成功的將button3的Text置為“Predicate的使用.”
下面是全部實(shí)現(xiàn)代碼:
復(fù)制代碼 代碼如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace DelegateIntegrateWinFormApp
{
    public partial class mainFrm : Form
    {
        public mainFrm()
        {
InitializeComponent();
        }
        private void mainFrm_Load(object sender, EventArgs e)
        {
/****************************注意例子中的使用方法****************
 * delegate TResult Func<TResult>();  無(wú)參,但是返回值為T(mén)Result類(lèi)型
 * delegate void Action<T>(T1 arg1);  有一個(gè)參數(shù)arg1,但是無(wú)返回值
 * delegate bool Predicate<T>(T arg);  有一個(gè)參數(shù)arg,返回bool類(lèi)型
 * **************************************************************/
        }
        #region 利用Func實(shí)現(xiàn)線(xiàn)程和界面交互
        private void AlternationUsingFunc(object text)
        {
//無(wú)參數(shù),但是返回值為bool類(lèi)型
this.Invoke(new Func<bool>(delegate()
{
    button1.Text = text.ToString();
    return true; //返回值
}));
        }
        private void AlternationUsingFuncThread()
        {
WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingFunc);
ThreadPool.QueueUserWorkItem(waitCallBack, "Func的使用");
        }
        private void button1_Click(object sender, EventArgs e)
        {
AlternationUsingFuncThread();
        }
        #endregion

        #region 利用Action實(shí)現(xiàn)線(xiàn)程和界面交互
        private void AlternationUsingAction(object text)
        {
//需要一個(gè)T類(lèi)型的參數(shù),無(wú)返回值
this.Invoke(new Action<object>(delegate(object myText)
{
    myText = text;
    button2.Text = text.ToString();
}),text);
        }
        private void AlternationUsingActionThread()
        {
WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingAction);
ThreadPool.QueueUserWorkItem(waitCallBack,"Action的使用");
        }
        private void button2_Click(object sender, EventArgs e)
        {
AlternationUsingActionThread();
        }
        #endregion
        #region 利用Predicate實(shí)現(xiàn)線(xiàn)程和界面的交互
        private void AlternationUsingPrecidate(object text)
        {
//需要一個(gè)T類(lèi)型的參數(shù),返回bool類(lèi)型
this.Invoke(new Predicate<object>(delegate(object myText) 
{
    myText = text;
    button3.Text = myText.ToString();
    return true;   //返回值
}),text);
        }
        private void AlternationUsingPrecidateThread()
        {
WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingPrecidate);
ThreadPool.QueueUserWorkItem(waitCallBack,"Predicate的使用");
        }
        private void button3_Click(object sender, EventArgs e)
        {
AlternationUsingPrecidateThread();
        }
        #endregion

    }
}


那么,現(xiàn)在對(duì)于WPF來(lái)說(shuō),該如何來(lái)使用呢?其實(shí)在WPF中,和winform中類(lèi)似,只是在WPF中要實(shí)現(xiàn)線(xiàn)程和界面的交互,我們需要用Dispatcher來(lái)實(shí)現(xiàn),也就是形如Control.Dispatcher.Invoke()的方式,由于與Winform實(shí)現(xiàn)方式無(wú)多大差別,這里我就直接附上全部代碼:
復(fù)制代碼 代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
InitializeComponent();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
/****************************注意例子中的使用方法****************
* delegate TResult Func<TResult>();  無(wú)參,但是返回值為T(mén)Result類(lèi)型
* delegate void Action();  無(wú)參,無(wú)返回值
* delegate bool Predicate<T>(T arg);  有一個(gè)參數(shù)arg,返回bool類(lèi)型
* 需要注意,與WinForm中不同的是,WPF中需要利用Control.Dispatcher.Invoke來(lái)實(shí)現(xiàn),其他類(lèi)似.
* **************************************************************/
        }
        #region 利用Func實(shí)現(xiàn)線(xiàn)程和界面交互
        private void AlternationUsingFunc(object text)
        {
//無(wú)參數(shù),但是返回值為bool類(lèi)型
button1.Dispatcher.Invoke(new Func<bool>(delegate()
{
    button1.Content = text.ToString();
    return true; //返回值
}));
        }
        private void AlternationUsingFuncThread()
        {
WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingFunc);
ThreadPool.QueueUserWorkItem(waitCallBack, "Func的使用");
        }
        private void button1_Click(object sender, RoutedEventArgs e)
        {
AlternationUsingFuncThread();
        }
        #endregion
        #region 利用Action實(shí)現(xiàn)線(xiàn)程和界面交互
        private void AlternationUsingAction(object text)
        {
//無(wú)參數(shù),無(wú)返回值
//button2.Dispatcher.Invoke(new Action(delegate()
//{
//    button2.Content = text.ToString();
//}));
//或者
button2.Dispatcher.Invoke((Action)(()=>
{
    button2.Content = text.ToString();
}));
        }
        private void AlternationUsingActionThread()
        {
WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingAction);
ThreadPool.QueueUserWorkItem(waitCallBack, "Action的使用");
        }
        private void button2_Click(object sender, RoutedEventArgs e)
        {
AlternationUsingActionThread();
        }
        #endregion
        #region 利用Predicate實(shí)現(xiàn)線(xiàn)程和界面的交互
        private void AlternationUsingPrecidate(object text)
        {
//需要一個(gè)T類(lèi)型的參數(shù),返回bool類(lèi)型
this.button3.Dispatcher.Invoke(new Predicate<object>(delegate(object myText)
{
    myText = text;
    button3.Content = myText.ToString();
    return true;   //返回值
}), text);
        }
        private void AlternationUsingPrecidateThread()
        {
WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingPrecidate);
ThreadPool.QueueUserWorkItem(waitCallBack, "Predicate的使用");
        }
        private void button3_Click(object sender, RoutedEventArgs e)
        {
AlternationUsingPrecidateThread();
        }
        #endregion

    }
}

逐個(gè)點(diǎn)擊界面上的按鈕,我們可以看到成功實(shí)現(xiàn)了線(xiàn)程和UI的交互:

當(dāng)然,上面我們只是說(shuō)到了在WinForm中和WPF中如何來(lái)使用的情況,代碼比較簡(jiǎn)單,也沒(méi)有具體的應(yīng)用場(chǎng)景,下面我們將結(jié)合中WPF來(lái)模擬一個(gè)具體的應(yīng)用場(chǎng)景:
現(xiàn)在假設(shè)我有一個(gè)txt文檔,名稱(chēng)為newEXO.txt,里面大概有5w行記錄,文件大小為30MB左右;同時(shí)我手邊還有一個(gè)oldEXO.txt里面也有5w數(shù)據(jù),但是其中有一些記錄和newEXO.txt中的不同,我現(xiàn)在需要對(duì)比兩個(gè)txt文檔,找出不同的記錄,并對(duì)不同的記錄進(jìn)行上色操作。
那么現(xiàn)在這里很明確了,我們需要兩個(gè)函數(shù),一個(gè)是讀取記錄的函數(shù)ChangeText(),一個(gè)是上色的函數(shù)ChangeColor()。
但是在實(shí)際操作中,發(fā)現(xiàn)如果我直接利用wpf讀取數(shù)據(jù)的話(huà),逐行讀取,耗時(shí)10s左右,也就是用戶(hù)界面會(huì)被阻塞10s,然后才會(huì)顯示給用戶(hù),這個(gè)體驗(yàn)性是相當(dāng)不好的,所以擬采用異步方式來(lái)導(dǎo)入數(shù)據(jù)。
同時(shí),考慮到差異比較也會(huì)比較耗時(shí),所以也準(zhǔn)備采用異步方式來(lái)進(jìn)行對(duì)比。

那么問(wèn)題來(lái)了,兩個(gè)均采用異步方式進(jìn)行,難免會(huì)發(fā)生數(shù)據(jù)未導(dǎo)入完成就開(kāi)始進(jìn)行差異比較的可能,所以這里還涉及到一個(gè)線(xiàn)程同步的問(wèn)題。
現(xiàn)在,這里有三個(gè)操作,異步的數(shù)據(jù)導(dǎo)入,異步的差異比較并上色,線(xiàn)程同步。

首先我們看異步導(dǎo)入,你也可以自己實(shí)現(xiàn)一個(gè)異步類(lèi),通過(guò)委托的BeginInvoke方法和EndInvoke方法來(lái)實(shí)現(xiàn)

復(fù)制代碼 代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ThreadSynchorous
{
    public  class AsyncInvoke
    {
        public void BeginAsync(Func<bool> MyFunction)
        {
            Func<bool> func = new Func<bool>(MyFunction);
            IAsyncResult iar = func.BeginInvoke(new AsyncCallback(EndAsync), func);
        }
        public void EndAsync(IAsyncResult iar)
        {
            Func<bool> func = (Func<bool>)iar.AsyncState;
            func.EndInvoke(iar);
        }
    }
}

由于Action委托的使用方式最為便捷,這里我采用Action委托方式來(lái)進(jìn)行,當(dāng)然了,:
復(fù)制代碼 代碼如下:

private void ChangeText()
        {
            this.button1.Dispatcher.Invoke((Action)(()=>
            {
                string filename = @"C:\newEXO.txt";
                using (StreamReader sr = new StreamReader(filename, Encoding.Default))
                {
                    string result;
                    while ((result = sr.ReadLine()) != null)
                    {
                        //here perform action
                    }
                }
                //label1.Dispatcher.Invoke((new Action(delegate()
                label1.Dispatcher.Invoke((Action)(()=>
                {
                    label1.Content += "Loading finish!(Thread.CurrentThreadName=" + Thread.CurrentThread.ManagedThreadId.ToString() + ") ";
                }));
            }));
        }

首先是當(dāng)點(diǎn)擊button1按鈕的時(shí)候,就啟動(dòng)ChangeText()函數(shù),也即數(shù)據(jù)導(dǎo)入函數(shù),然后label1會(huì)在加載完畢的時(shí)候,給出提示信息。
下面再看看ChangeColor()函數(shù):
復(fù)制代碼 代碼如下:

private void ChangeColor()
        {
            this.button1.Dispatcher.Invoke((Action)(()=>
            {
                this.button1.Background = Brushes.Red;
                //here perform large amount of data action and color the result
                label1.Dispatcher.Invoke((Action)(()=>
                {
                    label1.Content += "Coloring finish!(Thread.CurrentThreadName=" + Thread.CurrentThread.ManagedThreadId + ") ";
                }));
            }));
        }

可以看到也是當(dāng)button1點(diǎn)擊的時(shí)候,會(huì)觸發(fā)ChangeColor函數(shù)。由于二者操作比較耗時(shí),為了防止用戶(hù)界面阻塞,我們放到線(xiàn)程池中:
復(fù)制代碼 代碼如下:

ThreadPool.QueueUserWorkItem(o => ChangeText());
ThreadPool.QueueUserWorkItem(o => ChangeColor());

從上面可以看出,當(dāng)點(diǎn)擊按鈕button1的時(shí)候,兩個(gè)函數(shù)同時(shí)被引發(fā),也就是點(diǎn)擊按鈕的時(shí)候進(jìn)行如下操作:
復(fù)制代碼 代碼如下:

private void button1_Click(object sender, RoutedEventArgs e)
        {
            ThreadPool.QueueUserWorkItem(o => ChangeText());
            ThreadPool.QueueUserWorkItem(o => ChangeColor());
            label1.Content += " \r\n-------------------------\r\n";
        }

看到了什么?

看到了線(xiàn)程運(yùn)行的混亂,我們本想讓數(shù)據(jù)先加載,然后比較得出差異著色,可惜上面的結(jié)果中卻與想象中的相差甚遠(yuǎn).

這里的ChangeText()函數(shù)和ChangeColor()函數(shù)肯定不會(huì)像想象的那樣順序執(zhí)行,那么代碼就有問(wèn)題了,所以為了避免這個(gè)問(wèn)題,我們必須進(jìn)行線(xiàn)程同步,如何來(lái)進(jìn)行呢? 方法很多,這里我采用EventWaitHandle方式來(lái)進(jìn)行。

EventWaitHandle的Reset方式用來(lái)重置信號(hào)量,告訴其他運(yùn)行的進(jìn)程,你們需要被阻塞;Set方式用來(lái)釋放信號(hào)量,告訴其他運(yùn)行的進(jìn)程,你們的阻塞已經(jīng)被解除,可以繼續(xù)運(yùn)行了。

但是其他進(jìn)行通過(guò)什么來(lái)知道自己是否可以解除阻塞狀態(tài)呢? 那就是利用WaitOne方式來(lái)判斷:

也就是按照如下的代碼模式來(lái):

復(fù)制代碼 代碼如下:

EventWaitHandle waitMeHandle = new EventWaitHandle(false,EventResetMode.ManualReset);
private void ChangeText()
{
     waitMeHandle.Reset();  //即將進(jìn)入下列執(zhí)行過(guò)程,其他需要阻塞
  //....
     waitMeHandle.Set(); //釋放
}
private void ChangeColor()
{
      waitMeHandle.WaitOne(); //等待,直到接收到Set信號(hào),才能運(yùn)行
     //  ...
}

當(dāng)然上面我舉出的例子只是一個(gè)Sample,我寫(xiě)過(guò)這個(gè)軟件,利用的是BeginInvoke和EndInvoke方式實(shí)現(xiàn)的異步調(diào)用,有興趣可以參見(jiàn)我的這篇文章中提到的軟件:
下面是軟件截圖:

另外在寫(xiě)這篇文章的時(shí)候,我在StackOverFlow上面有過(guò)提問(wèn),就是關(guān)于當(dāng)前的Thread的ThreadId為什么一致的問(wèn)題, 應(yīng)該說(shuō)兩個(gè)函數(shù)放到了ThreadPool中,結(jié)果出來(lái)的ThreadId應(yīng)該不一樣才對(duì)呀.

其實(shí),正確的答案是我的打印出ThreadId的信息都放在了label1.Dispatcher.Invoke這句話(huà)中,而這個(gè)Lable1屬于界面UI,也就是前臺(tái)線(xiàn)程,所以ThreadId會(huì)是一樣的,如果你直接在進(jìn)入函數(shù)的時(shí)候,輸出ThreadId,你就會(huì)發(fā)現(xiàn)兩個(gè)函數(shù)運(yùn)行在不同的線(xiàn)程上了.

下面是全部代碼:

復(fù)制代碼 代碼如下:

using System;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Threading;
using System.IO;
namespace ThreadSynchorous
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            asyncInvoke = new AsyncInvoke();
        }
        AsyncInvoke asyncInvoke;
        EventWaitHandle waitMeHandle = new EventWaitHandle(false,EventResetMode.ManualReset);
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            ThreadPool.QueueUserWorkItem(o => ChangeText());
            ThreadPool.QueueUserWorkItem(o => ChangeColor());
            label1.Content += " \r\n-------------------------\r\n";
        }

        private void ChangeText()
        {
            waitMeHandle.Reset();  //即將進(jìn)入下列執(zhí)行過(guò)程,其他需要阻塞
            this.button1.Dispatcher.Invoke((Action)(()=>
            {
                string filename = @"C:\MyLearn\eqrms_hk_20111219_listedposn_ff\EQRMS_HK_20111219_EXO.txt";
                using (StreamReader sr = new StreamReader(filename, Encoding.Default))
                {
                    string result;
                    while ((result = sr.ReadLine()) != null)
                    {
                        //here perform action
                    }
                }
                label1.Dispatcher.Invoke((Action)(()=>
                {
                    label1.Content += "Loading finish!(Thread.CurrentThreadName=" + Thread.CurrentThread.ManagedThreadId.ToString() + ") ";
                    waitMeHandle.Set(); //釋放
                }));
            }));
        }

        private void ChangeColor()
        {
            waitMeHandle.WaitOne(); //等待,直到接收到Set信號(hào),才能運(yùn)行
            this.button1.Dispatcher.Invoke((Action)(()=>
            {
                this.button1.Background = Brushes.Red;
                //here perform large amount of data action and color the result
                label1.Dispatcher.Invoke((Action)(()=>
                {
                    label1.Content += "Coloring finish!(Thread.CurrentThreadName=" + Thread.CurrentThread.ManagedThreadId + ") ";
                }));
            }));
        }
    }
}

本文中涉及到的源碼,可以從這里下載

 

相關(guān)文章

  • C# 單元測(cè)試全解析

    C# 單元測(cè)試全解析

    這篇文章主要介紹了C# 單元測(cè)試的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-04-04
  • C#程序員統(tǒng)計(jì)自己的代碼行數(shù)

    C#程序員統(tǒng)計(jì)自己的代碼行數(shù)

    這篇文章給大家講解了下作為程序員如何統(tǒng)計(jì)自己寫(xiě)過(guò)的代碼的行數(shù),這個(gè)也是證明自己程序員能力的一個(gè)表現(xiàn),一起來(lái)看下。
    2017-12-12
  • 基于WPF封裝一個(gè)可擴(kuò)展的Window

    基于WPF封裝一個(gè)可擴(kuò)展的Window

    WPF中Window相信大家都很熟悉,有時(shí)我們有一些自定義需求默認(rèn)Window是無(wú)法滿(mǎn)足的,所以本文就來(lái)和大家聊聊WPF如何封裝一個(gè)可擴(kuò)展的Window吧
    2024-04-04
  • C#中try...catch的使用與常見(jiàn)面試題分享

    C#中try...catch的使用與常見(jiàn)面試題分享

    這篇文章首先給大家介紹了關(guān)于C#中try...catch的語(yǔ)法,而后又給大家分享了關(guān)于C#中try...catch最常見(jiàn)的面試題,具有一定的參考借鑒價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-02-02
  • C#控件picturebox實(shí)現(xiàn)圖像拖拽和縮放

    C#控件picturebox實(shí)現(xiàn)圖像拖拽和縮放

    這篇文章主要為大家詳細(xì)介紹了C#控件picturebox實(shí)現(xiàn)圖像拖拽和縮放,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • C#中的虛函數(shù)virtual

    C#中的虛函數(shù)virtual

    這篇文章介紹了C#中的虛函數(shù)virtual,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • Unity實(shí)現(xiàn)簡(jiǎn)單虛擬搖桿

    Unity實(shí)現(xiàn)簡(jiǎn)單虛擬搖桿

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)簡(jiǎn)單虛擬搖桿,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • 不用IDE寫(xiě)C#的Hello World的方法

    不用IDE寫(xiě)C#的Hello World的方法

    這篇文章主要介紹了不用IDE寫(xiě)C#的Hello World的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-10-10
  • C# List介紹及具體用法

    C# List介紹及具體用法

    這篇文章主要介紹了C# List介紹及具體用法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • c#字符長(zhǎng)度查詢(xún)代碼

    c#字符長(zhǎng)度查詢(xún)代碼

    下面的代碼用了查詢(xún)字符串中的一些類(lèi)型,需要的朋友可以參考下
    2012-06-06

最新評(píng)論