匿名方法其实是将方法定义与委托变量赋值两个步骤结合在一起
如果一个方法拥有一个委托类型的参数,则调用此方法时,可以直接将一个匿名方法作为方法实参:
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();
}
}
}
利用委托实现回调:
实现回调最直观的方法是使用委托,示例代码:
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 }
定时回调:
如果需要以固定的时间间隔调用某个方法,可以利用.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、其他书上的。