理解:
委托对于新手而言,理解起来还是有困难的,网上也有很多的比喻,在委托和多线程结合时,就是把委托比喻成为一个中介商,在线程交互Ui控件的数据时,你会发现,需要用到委托,在新线程调用me.invoke(委托,参数,参数),于是乎,Me.invoke就将数据传到ui控件,这是通过委托的方式,就有新线程不能直接操控控件,通过委托人,将数据送到控件。假如不用委托,那么报出的错误时,从不是创建线程访问控件。而me.invoke实际上就是将线程转为创建线程来访问控件,控件的创建线程就是窗体或者控件.invoke.都可以,一句话就是哪个对象调用invoke就把委托对应的过程回调到创建对象所在的线程执行。.net也推荐这种方式进行跨线程的控件操作。
委托实际上不仅仅用于线程,委托实质只是一个类型delegate,而这个类型封装了函数地址,你看到的addressof关键字就是进行函数地址的获取。拥有了函数地址,我们就能对其进行回调。用回调的方式的还有事件的方式。addhandler 事件,addressof 过程。
使用
1.多线程结合委托操作控件
本节不是主讲多线程,所以不会多赘述它。
Imports System.Threading
Public Class Form1
Delegate Sub Mydelegate(data As String) '声明一个委托
Private Sub RefereshCtrl(data As String) '委托对应的过程
Label1.Text = data
End Sub
Private Sub NewThread() '创建的新线程
For i = 0 To 100
Me.Invoke(New Mydelegate(AddressOf RefereshCtrl), i.ToString) '使用委托方式回调刷新控件的过程
Thread.Sleep(1000) '延时一秒刷新
Next
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim t As New Thread(AddressOf NewThread)
t.Start() '开始线程
End Sub
End Class
很显然lable用了委托后能够刷新数据,不卡ui.
2.委托用于Linq
使用linq前需要了解lambda即匿名函数。
lambda分为单行lambda和多行lambda
Dim testsinglelambda = Sub(test As String) Debug.WriteLine(test)
Dim testMutillinelambda = Sub(test As String)
Debug.WriteLine(test)
End Sub
testsinglelambda("这是一个单行lambda")
testMutillinelambda("这是一个lambda")
如上即是简单的lambda了。若要有返回值的lambda就用类似dim fuc=function() return xx
即是把sub改为funciton,加个返回值,和我们定义的sub和function但它没有名称,所以称为匿名。
到这里你会问,lambda和委托是什么关系呢?
这里我用反射给你看看它的真面目。
Dim testsinglelambda = Sub(test As String) Debug.WriteLine(test)
Dim lambdatype = testsinglelambda.GetType
Dim lambdabasetype = lambdatype.BaseType
Dim lambdabasetypebasetype = lambdabasetype.BaseType
Debug.WriteLine("lambda继承:{0}->{1}->{2}", lambdatype.Name, lambdabasetype.Name, lambdabasetypebasetype.Name)
这里我用反射获取其父类的父类。
继承关系如图,匿名委托->多播委托->委托。
所以我们可以知道lambda本身就是属于委托类型,也就不奇怪于lambda.invoke这个方法了。
你也可以用lambda替代me.invoke中的委托即me.invoke(lambda)
在.net中内置了多个action,和多个func,这些都属于委托类型。linq也是基本传入这些参数类型的委托。
一个简易的linq示例如下。
Dim linqlist = Enumerable.Range(0, 80) '生成80个数字
Dim result = linqlist.Where(Function(x) x > 50) '筛选大于50的整数
For Each item As Integer In result
Debug.Write(item & vbTab) '输出结果
Next
输出结果如图。这里的委托返回的是一个Boolean值,linq通过判断这个值来对集合进行一个筛选。
这也可以启发我们,用委托作为参数传入到过程中,我们不需要关注外界怎样的过程只需要使用委托返回的结果进行判断即可。
接下来我做个简单的示例模仿Linq筛选条件的过程
Private Function 筛选(Of T)(sourcelist As IEnumerable(Of T), fuc As Func(Of T, Boolean)) As IEnumerable(Of T)
Dim result As New List(Of T)
For Each item As T In sourcelist
If fuc(item) Then
result.Add(item)
End If
Next
Return result
End Function
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim linqlist = Enumerable.Range(0, 80)
Dim result = 筛选(Of Integer)(linqlist, Function(x) x > 70)
For Each item As Integer In result
Debug.Write(item & vbTab)
Next
End Sub
这是一个筛选x>70的模仿Linq。
结果:
这里用了泛型目的是让筛选的过程可以适用于所有类型,再配上泛型委托func简直就是能够适用于所有需要筛选的过程。
看到这里,我相信你能看到了委托的强悍的地方,那就是提供一个不限思想的空间给用户写过程,而它只需要用invoke即可,提高了代码的复用性,提高了开发效率,一套代码多处使用。再加上委托用的是lambda写起来又很方便。
舒服到无法自拔的操作,强烈推荐。
由于篇幅有限,使用委托的地方实在太多这里仅用了几个经典的地方使用它,委托你甚至可以用于控件的属性。具体得给读者开发了。
此处涉及内容有反射,lambda,linq,多线程,希望不太懂的去了解一下相关知识