将C#函数转换为VB.Net,Lambda问题和转换的最佳方式

时间:2013-05-06 19:50:17

标签: c# vb.net

我正在尝试将VS2010 C#4.0框架的代码块转换为VS2008 VB.NET 3.5 Framework。我非常不确定如何继续,因为我不熟悉VB.NET和VS2008,我发现两种环境之间的差异令人沮丧。我已经从最初的C#中剔除了大部分不相关的代码,希望能够提供一个可以指出解决方案的问题的清晰示例。

我确实尝试了一些代码转换器,但是lambdas将它们绊倒了。

我将第一个lambda转换为一个简单的For Each构造,看起来很好。 然而,第二个lambda(传递给ThreadPool.QueueUserWorkItem调用)引起了我的不确定性。由于lambda正在使用在lambda体外声明的taskcount var,我对使这个代码对我的目标环境(VS2008 / VB.Net / 3.5)友好并保持代码的最佳方法犹豫不决与原始实现尽可能相似。除非没有其他办法,否则我不希望明确将taskcount推送到WaitCallback

public void sendAndBlock(List<ISendable> msgs)
{
    int taskCount = msgs.Count;
    AutoResetEvent fini = new AutoResetEvent(false);
    msgs.ForEach(m =>
    {
        ThreadPool.QueueUserWorkItem(nil =>
        {
            this.send(m);
            //threadsafe decrement and if we have no tasks left then unblock.
            if (0 == Interlocked.Decrement(ref taskCount))
            {
                fini.Set();//signal our main thread to proceed
            }
        }, m);
    });
    //block our main thread
    fini.WaitOne();
}

2 个答案:

答案 0 :(得分:4)

不幸的是,与Visual Studio 2008一起使用的VB版本将要求你将其分解为三个方法(原始的,每个lambda表达式加一个),因为旧版本的VB.Net还不支持多个-line lambda表达式。我们必须调整一些东西,这样我们就可以将lambda表达式放到一行中,以便正确地关闭捕获的变量。如果您使用相同版本的Visual Studio,VB.Net将能够以与C#相同的方式执行此操作(至少在本例中),因为Visual Studio 2010中包含的VB.Net版本支持多个-line lambda表达式。

我认为这样做会,但检查一下:我在回复窗口输入了所有这些并且它很复杂我可能有一两个错误。

Public Sub sendAndBlock(ByVal msgs As List(Of ISendable))

   Dim taskCount As Integer = msgs.Count
   Dim fini As New AutoResetEvent(False)

   'vb.net for vs2008 is limited to single-line lambdas.
   ' But we still need to create a closure to capture the fini and taskCount variables
   ' Means we can't translate old code line-for-line
   ' Solution is to abstract the old lambda expressions out to their own methds that we can call in a single line
   msgs.ForEach(Function(m) QueueMessage(m, fini, taskCount))

   fini.WaitOne()

End Sub

Private Sub QueueMessage(ByVal msg As ISendable, ByVal signaler As AutoRestEvent, ByRef taskCount As Integer)
    ThreadPool.QueueUserWorkItem(Function(n) SendQueuedMessage(msg, taskCount, signaler), msg);
End Sub

Private Sub SendQueuedMessage(ByVal msg As ISendable, ByRef TaskCount As Integer, ByVal signaler As AutoResetEvent)
    Me.send(msg)
    'Not sure about this line, because `Set` is a reserved word in VB
    If Interlocked.Decrement(taskCount) = 0 Then signaler.Set()
End Sub

我或许可以将其归结为两种方法而不是三种方法,因为其中一种额外的方法缩减为一行,但为了简单和可读性,我将把它留在这里。

最后,如果能够从Visual Studio 2010中定位.Net 3.5就足够了,您可以使用更接近原始内容的东西,因为您可以使用Visual Studio 2010中较新的VB语言语法功能.Net 3.5。

答案 1 :(得分:-1)

Public Sub sendAndBlock(msgs As List(Of ISendable))
    Dim taskCount As Integer = msgs.Count
    Dim fini As New AutoResetEvent(False)
    msgs.ForEach(Function(m) 
    ThreadPool.QueueUserWorkItem(Function(nil) 
                                     Me.send(m)
                                     'threadsafe decrement and if we have no tasks left then unblock.
                                     If 0 = Interlocked.Decrement(taskCount) Then
                             'signal our main thread to proceed
                                     fini.[Set]()
                                     End If

                                 End Function, m)

                End Function)
    'block our main thread
    fini.WaitOne()
End Sub

谢谢,DeveloperFusion