C#委托(3)


匿名方法其实是将方法定义与委托变量赋值两个步骤结合在一起

如果一个方法拥有一个委托类型的参数,则调用此方法时,可以直接将一个匿名方法作为方法实参:     

public delegate int AddDelegate(int val1,int val2);
void Cal(AddDelegate del,int i,int j)
{
label1.Text
=string.Format("10+22={0}",del(i,j));
}
void MainFormLoad(object sender,EventArgs e)
{
Cal(
delegate(int i,int j){return i+j;},10,22);
}

Lambda表达式:
Lambda在C#3.0中引入,是匿名方法的进一步简化,可以用于定义一个匿名函数,并将其传送给一个委托变量。示例代码:    

public delegate string SomeDelegateType(int arguments);
SomeDelegateType del
=arguments=>{return arguments.ToString();};
void MainFormLoad(object sender, EventArgs e)
{ label1.Text
=del(5); }


委托变量赋值语句可进一步简化为:

 

SomeDelegateType del=arguments=>arguments.ToString();


Lambda表达式的两种基本格式:
(1)(input parameters)=>表达式
(2)(input parameters)=>{语句1;语句2;……}
下面是一些Lambda表达式的编写方法:

public delegate TResult Func<TResult>();
public delegate TResult Func<T,TResult>(T arg);
public delegate TResult Func<T1,T2,TResult>(T1 arg1,T2 arg2);
void MainFormLoad(object sender, EventArgs e)
{
Func
<string> del1=()=>"Func delegate1";
Func
<int,string> del2=(str)=>str.ToString();
Func
<double, double, int> del3=(d1,d2)=>{return (int)(d1+d2);};
StringBuilder strBuilder
=new StringBuilder();
strBuilder.AppendLine(
string.Format("Func<string>:{0}",del1()));
strBuilder.AppendLine(
string.Format("FFunc<int 5,string>:{0}",del2(5)));
strBuilder.AppendLine(
string.Format("Func<double 33,double 12,int>:{0}",del3(33,12)));
label1.Text
=strBuilder.ToString();
}

 



回调:
回调可以解决“延迟调用对象方法”问题,例如希望在某个场景或满足某些条件时菜调用此对象的方法

.NET中实现回调的典型方法:基于接口的回调、利用委托实现回调、定时回调、多线程回调

 

基于接口的回调:
先创建一个回调对象,然后创建一个控制器对象,将回调对象需要被调用的方法告诉控制器对象。控制器对象负责检查某个场景是否出现或是否满足某个条件。当此场景出现或此条件满足时,自动调用回调对象的方法。
示例代码:

    public partial class MainForm : Form
    {
        void MainFormLoad(object sender, EventArgs e)
        {
            Controler c=new Controler(new CallBackClass());
            Timer t=new Timer();
            t.Interval=1000;
            t.Tick+= delegate { c.Begin();};
            t.Start();
        }
    }
    interface ICallBack
    {
        void Run();
    }
    class CallBackClass:ICallBack
    {
        public void Run()
        {
            MessageBox.Show(string.Format("second:{0}", DateTime.Now.Second));
        }
    }
    class Controler
    {
        private ICallBack CallBackObject=null;
        public Controler(ICallBack obj)
        {this.CallBackObject=obj;}
        public void Begin()
        {
            if(DateTime.Now.Second%3==0)
            {
                CallBackObject.Run();
            }
        }
    }
上述代码中定义了一个接口ICallBack,类CallBackClass继承了此接口并写入了Run()方法,类Controler用来定义回调实现方案,如果此时秒数是3的倍数,就触发回调对象
这是单个回调的实现例子

利用委托实现回调:
实现回调最直观的方法是使用委托,示例代码:

1 public delegate void ShowTimeDelegate();
2  class A
3 {
4 public void AShowTime()
5 { MessageBox.Show("A:"+DateTime.Now.ToLongTimeString());}
6 }
7  class B
8 {
9 public static void BShowTime()
10 {MessageBox.Show("B:"+DateTime.Now.ToLongTimeString());}
11 }
12  class Controler
13 {
14 private ShowTimeDelegate d;
15 public void RegisterDelegateForCallBack(ShowTimeDelegate method)
16 {d+=method;}
17 public void UnregisterDelegateForCallBack(ShowTimeDelegate method) {d-=method;}
18 public void CallBack()
19 {
20 if(d!=null)
21 d.Invoke();
22 }
23 }
24 void MainFormLoad(object sender, EventArgs e)
25 {
26 A a=new A();
27 Controler c=new Controler();
28 c.RegisterDelegateForCallBack(a.AShowTime); c.RegisterDelegateForCallBack(B.BShowTime);
29 Timer t=new Timer();
30 t.Interval=1000;
31 t.Tick+= delegate {if(DateTime.Now.Second%3==0)c.CallBack(); };
32 t.Start();
33 }

 

       

定义需要回调的对象AB,Controler类用来添加删除回调对象,有一个触发方法CallBack(),当满足条件秒数为3的倍数时调用所有的回调方法d.Invoke()

定时回调:
如果需要以固定的时间间隔调用某个方法,可以利用.NET Framework提供的Timer类,它可以定时回调一个满足TimerCallBack委托要求的方法,此委托定义如下:

 

public delegate void TimerCallback(Object state);


参数Object类型的state作为回调方法的实参传递
利用System.Threading命名空间的Timer类实现定时回调

public System.Threading.Timer(TimerCallback callBack,Object state,int dueTime,int period)

callBack:要定时回调的方法
state:要传递的参数
dueTime:调用延迟
period:调用间隔


此委托定义了一个Object类型的方法参数,此参数将作为回调方法的实参传递,例子:    

static void ShowTime(Object ti)
{
TaskInfo obj
=ti as TaskInfo;
obj.count
++;
MessageBox.Show(obj.count.ToString());
}
class TaskInfo
{
public int count=0;
}
void MainFormLoad(object sender, EventArgs e)
{
TaskInfo t
=new TaskInfo();
System.Threading.Timer timer
=new System.Threading.Timer(ShowTime,t,0,1000);
}

     

无须多解释,代码够简洁

多线程回调:
在多线程环境中,应用程序主线程通常都会启动一些辅助线程在后台完成特定的工作,这就带来了一个“主线程在辅助线程工作结束后如何取回其结果”的问题。这是就用到了多线程回调。
先看一个多线程回调的代码:

        static int[] CreateIntArray()
        {
            int[] arrs=new int[10];
            Random r=new Random();
            for(int i=0;i<10;i++)
                arrs[i]=r.Next(0,100);
            return arrs;
        }
        static void ShowArray(int[] arr)
        {
            string str="";
            for(int i=0;i<10;i++)
                str+=string.Format("({0})={1}  ",i,arr[i]);
            MessageBox.Show(str);
        }
        class MyThread{
            public Func<int[]> createArr;
            public Action<int[]> showArr;
            //threading function
            public void SortArray(){
                int[] arr=createArr();
                showArr(arr);
                //sort array
                //ShowArray(arr);
            }
        }
        void MainFormLoad(object sender, EventArgs e)
        {
            MyThread t=new MainForm.MyThread();
            t.createArr=CreateIntArray;
            t.showArr=ShowArray;
            Thread thread=new Thread(t.SortArray);
            thread.Start();
   }

先定义了两个待回调的方法,然后定义了一个MyThread类,里面有两个委托和数据处理方法,作为线程处理方法,然后启动线程
MyThread方法用来查看线程处理结果,即辅助线程工作结束后应该返回的结果

作者注:MyThread类中有两个委托类型的字段用于接受外界传入的方法,然后在该线程函数SortArray中使用这两个字段。
SoryArray方法并不知道也不关心外界传入的方法,她只是简单的通过委托调用这两个方法,这正是使用“回调”的典型代码


还涉及到异步回调的问题,后面再理解吧。

做笔记的好处是可以比较细的过书上写的东西,预留了思考空间,就像上面的“回调”的典型代码,使用委托回调更方便程序改动。

下期预告:事件及事件驱动
同样取自:《.NET4.0面向对象编程漫谈 基础篇》
当然最好各取所长,同事看看MSDN、其他书上的。

posted @ 2011-06-27 15:12  L Cooper  阅读(543)  评论(0编辑  收藏  举报