Vb.net多线程条件下,给委托方法传参数

来源:互联网 发布:文怀沙 知乎 编辑:程序博客网 时间:2024/04/28 13:17
晚上回家写...
  呵呵,放了这么久鸽子,主要是因为自己对委托的了解还不是特别的深刻,另外需要读一些C#代码,对C#的一些细节了解的也不够。借口应该够充分了。
  那好,正经事,先说委托。
 委托是一种数据结构,它引用静态(shared in Vb/static inC#)方法或引用类实例及该类的实例方法。委托其实就是类似C++的函数指针,只是它安全性更好...如此云云。更多的资料参考参考资料【1】和【2】【6】这三部分的内容。个人感觉委托这地方有点乱,主要是因为设计函数过程操作,另外Vb和C#在实现细节上也有很多的不同。另外,在声明上总有点别扭。了解c++的,直接把它当指针最好,那样好理解点。
  委托说完了,再来看看线程
  Thead,线程。一个进程里可以构建很多的线程,从而更好的提高进程性能和响应能力,更细致的看baidu百科,那的资料更全面。:)
  threadpool,线程池,可用于发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。参考【3】
  名词解释完了,写段样例代码,正常的带参数的委托代码,只是用于表述带参数委托的使用。可能设计上有不妥的地方,没有仔细推敲。
Module Module1
    Public Class Dog
        Sub New()
            Me._hungry = True
        End Sub

        Sub New(ByVal Name As String)
            Me._name = Name
            Me._hungry = True
        End Sub

        Private _name As String
        Public Property Name() As String
            Get
                Return _name
            End Get
            Set(ByVal value As String)
                _name = value
            End Set
        End Property

        Private _hungry As Boolean
        Public Property Hungry() As Boolean
            Get
                Return _hungry
            End Get
            Set(ByVal value As Boolean)
                _hungry = value
            End Set
        End Property

        '重写Object的Tostring方法
        Public Overrides Function Tostring() As String
            Return Me.Name
        End Function
    End Class

    ''' <summary>
    ''' 静态方法封装类
    ''' </summary>
    ''' <remarks></remarks>
    Public Class SharedFunc
        Public Shared Sub Feed(ByVal Obj As Dog)
            If Obj.Hungry Then
                Console.Write("Feed" & Obj.Tostring())
                Obj.Hungry = False
            End If

        End Sub
    End Class

    Delegate Sub MyDelegate(ByVal Obj As Dog)

    Sub Main()
        Dim MyFeed As New MyDelegate(AddressOf SharedFunc.Feed)
        Dim DaH As Dog = New Dog("DaHuang")
        MyFeed(DaH)

    End Sub

End Module
还是纯阐述概念,现在我们打算Feed很多只小狗,于是我们把多线程技术加到上面的代码里,主要修改main()过程
    <MTAThread()> _
    Sub Main()
        'Dim MyFeed As New MyDelegate(AddressOf SharedFunc.Feed)
        Dim DaH As Dog = New Dog("DaHuang")
        DaH.Hungry = True
        'MyFeed(DaH)
        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf SharedFunc.Feed(DaH)))
    End Sub
等等,这样的代码IDE提示,"Addressof"操作数必须是某个方法的名称。其实在上面的代码里,Waitcallback本身是个委托类型,Addressof应该接函数的地址,当然没有办法传参数了。
而WaitcallBack是框架定义的委托类型。

看看WaitcallBack的委托定义。
<ComVisibleAttribute(True)> _
Public Delegate Sub WaitCallback ( _
state As Object _
)

state as object ? 这个是做什么的?

包含回调方法要使用的信息的对象。正是它。再看看QueueUserWorkItem重载了两个函数。呵呵Object?和我们传的类型不符?这个不困难,只要转换就好。

为了保持委托函数与委托的一致性,需要适当修改下委托函数的参数代码,毕竟State是Object对象。新的多线程代码

Imports system.Threading

Module Module1

    Public Class Dog
        Sub New()
            Me._hungry = True
        End Sub

        Sub New(ByVal Name As String)
            Me._name = Name
            Me._hungry = True
        End Sub

        Private _name As String
        Public Property Name() As String
            Get
                Return _name
            End Get
            Set(ByVal value As String)
                _name = value
            End Set
        End Property

        Private _hungry As Boolean
        Public Property Hungry() As Boolean
            Get
                Return _hungry
            End Get
            Set(ByVal value As Boolean)
                _hungry = value
            End Set
        End Property

        '重写Object的Tostring方法
        Public Overrides Function Tostring() As String
            Return Me.Name
        End Function
    End Class

    ''' <summary>
    ''' 静态方法封装类
    ''' </summary>
    ''' <remarks></remarks>
    Public Class SharedFunc
        Public Shared Sub Feed(ByVal Obj As Object)
            If Obj Is Nothing Then
                Console.Write("Obj is nothing")
            Else
                Obj = Convert.ChangeType(Obj, GetType(Dog))
            End If
            If Obj.Hungry Then
                Console.Write("Feed" & Obj.ToString())
                Obj.Hungry = False
            End If

        End Sub
    End Class

    'Delegate Sub WaitCallback(ByVal Obj As Dog)

    <MTAThread()> _
    Sub Main()
        'Dim MyFeed As New MyDelegate(AddressOf SharedFunc.Feed)
        Dim DaH As Dog = New Dog("DaHuang")
        'MyFeed(DaH)
        DaH = DirectCast(DaH, Object)
        Dim xiaoB As Dog = New Dog("XiaoBai")
        xiaoB = DirectCast(xiaoB, Object)
        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf SharedFunc.Feed), DaH)
        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf SharedFunc.Feed), xiaoB)
        'Thread.Sleep(1000)


    End Sub
End Module


这样就实现了代码的多线程化。

后续的一些讨论,如果传的参数不是一个,而是多个,该如何处理?

这个问题比较简单,从这也能看出微软工程师在设计上的巧妙之处,因为在.net中所有的对象都是继承自Object对象。这么做,使State对象有了最大的适应性。(写跑了好像?)当需要传多个参数时,只需要把这些参数封装成一个类对象就可以了。然后把封装后的对象传进去。


下面发个C#的实现,C#在重写Tostring()后,和字符串拼接和VB.net有些区别,不是重点,所以省去那个重写方法

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;


namespace DelegateCSharp
{
    public class Dog
     {
          public Dog()
         {
             this._hungry = true;
         }
       
         public Dog(string Name)
         {
             this._name = Name;
             this._hungry = true;
         }
       
         private string _name;
         public string Name {
             get { return _name; }
             set { _name = value; }
         }
       
         private bool _hungry;
         public bool Hungry {
             get { return _hungry; }
             set { _hungry = value; }
         }    
     }
   
     /// <summary>
     /// 静态方法封装类
     /// </summary>
     /// <remarks></remarks>
     public class SharedFunc
     {
         public static void Feed(Dog Obj)
         {
             if (Obj.Hungry) {
                 Console.Write("Feed" + Obj.Name);
                 Obj.Hungry = false;
             }
           
         }
     }
    
   class Program
   {
        [MTAThread()]
        static void Main(string[] args)
        {
         Dog DaH = new Dog("DaHuang");
         //MyFeed(DaH)
         //DaH = (object)DaH;
         Dog xiaoB = new Dog("XiaoBai");
         //xiaoB = (object)xiaoB;
         ThreadPool.QueueUserWorkItem(delegate { SharedFunc.Feed(DaH); });
         ThreadPool.QueueUserWorkItem(delegate { SharedFunc.Feed(xiaoB); });
         Thread.Sleep(1000);
        }
    }
}
这段C#代码和前面的Vb.net代码实现是一样的。但你是否发现C#的代码要比VB.Net代码简洁很多,并没有使用类型转换的部分,取而代之的是一句.

ThreadPool.QueueUserWorkItem(delegate { SharedFunc.Feed(DaH); });

玄机就在这delegate后边的{},正是这个{}实现了函数过程的直接带参数调用

C#如此方便,并不是因为C#的Delegate比VB.net的先进,而是C#支持匿名方法【4】,所谓匿名方法就是没有名的方法,这点和匿名变量是一样的。{}和它里面的内容,就是一个匿名方法。由此可见,因为C#支持匿名方法所带来的便捷。
那VB.net就没有办法了?很可惜的说,对于2002、2003、2005,起码我还没有找到更合适的办法。不过值得庆幸的是。VB.Net 2008开始支持lambda表达式。看CSDN论坛里有人用lambda表达式来写。具体怎么写,找不到了。关于Lambda表达式的资料参考【5】.通过Lambda表达式也可以实现类似匿名函数这样的写法,不过可能只能实现一行函数代码的书写,不适合多行。因为现在还在用2005,关于lambda的部分有待日后探讨。


参考资料:
【1】Delegate类
http://msdn.microsoft.com/zh-cn/library/system.delegate(VS.80).aspx

【2】委托(C#)
http://msdn.microsoft.com/zh-cn/library/900fyy8e(VS.80).aspx

【3】Threadpool类
http://msdn.microsoft.com/zh-cn/system.threading.threadpool.aspx

【4】C# 匿名方法
http://msdn.microsoft.com/zh-cn/library/0yw3tz5k(VS.80).aspx

【5】Lambda 表达式
http://msdn.microsoft.com/zh-cn/magazine/cc163362.aspx

【6】何时使用委托而不使用接口(C# 编程指南)
http://msdn.microsoft.com/zh-cn/library/ms173173(VS.80).aspx
原创粉丝点击