[Resolved] C# to VB Adaption Problem with Lambda Expressions
-
Hi guys, I hope you had a nice start into 2012! I've been trying to convert this^ piece of code into VB, using VS Express 2010 and #Develop. In order to avoid problems with conversion of c# 'yield' operator, I put the extensions into a DLL and set a reference to that. The translated code of the test implementation reads like:
Shared Sub Main(ByVal args() As String)
Dim worker As New BackgroundWorker()
worker.WorkerReportsProgress = True
AddHandler worker.DoWork, Function(sender, e)
' pretend we have a collection of items to process
Dim items(999) As Integer
items.WithProgressReporting(Function(progress) worker.ReportProgress(progress)).ForEach(Function(item) Thread.Sleep(10)) ' simulate some real work
End FunctionAddHandler worker.ProgressChanged, Function(sender, e) ' make sure the figure is written to the ' same point on screen each time Console.SetCursorPosition(1, 0) Console.Write(e.ProgressPercentage) End Function worker.RunWorkerAsync() Console.Read()
End Sub
Unfortunately in VB the line
items.WithProgressReporting(Function(progress) worker.ReportProgress(progress).ForEach(Function(item) Thread.Sleep(10)))
throws an exception "Expression does not produce a value" at the underlined place. There's no such exception in C# where the test code compiles and executes fine. Having to implement the technique into my VB application, I'd like to understand where the problem arises. Could anyone of you tell me what's wrong in the (automatic) translation of the Lambda expression? Thank you Mick
I always have trouble with anonymous delegates in VB so I factored them out :
Class Program
Shared worker As BackgroundWorker
Public Shared Sub Main() 'ByVal args As String())
worker = New BackgroundWorker()
worker.WorkerReportsProgress = True
AddHandler worker.DoWork, AddressOf DoWork
AddHandler worker.ProgressChanged, AddressOf ProgressChanged
worker.RunWorkerAsync()
Console.Read()
End SubPrivate Shared Sub DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Dim items = Enumerable.Range(1, 1000) items.WithProgressReporting(AddressOf ReportProgress).ForEach(AddressOf DoSleep) End Sub Private Shared Sub ReportProgress(ByVal progress As Integer) worker.ReportProgress(progress) End Sub Private Shared Sub DoSleep(ByVal item As Integer) Thread.Sleep(10) End Sub Private Shared Sub ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Console.SetCursorPosition(1, 0) Console.Write(e.ProgressPercentage) End Sub
End Class
Cheers
-
Eddy Vluggen wrote:
How did you resolve the fact that VB.NET lacks a "yield return" statement?
perhaps with patience. Yield exists since VS2010 SP1 according to this[^]. And it is simply
yield
, notyield return
, so for once VB.NET is less verbose than C#. :)Luc Pattyn [My Articles] Nil Volentibus Arduum
Hey just wanted to say thanks Luc that link got me to several other links on the subject and could prove quite useful to me in the very near future. Thanks again. This is now supported in VS 2010 SP1, with the Async CTP, see: http://msdn.microsoft.com/en-us/vstudio/gg497937[^] Also see: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=4738205d-5682-47bf-b62e-641f6441735b&displaylang=en[^]
"If you think it's expensive to hire a professional to do the job, wait until you hire an amateur." - Red Adair
-
Hi guys, I hope you had a nice start into 2012! I've been trying to convert this^ piece of code into VB, using VS Express 2010 and #Develop. In order to avoid problems with conversion of c# 'yield' operator, I put the extensions into a DLL and set a reference to that. The translated code of the test implementation reads like:
Shared Sub Main(ByVal args() As String)
Dim worker As New BackgroundWorker()
worker.WorkerReportsProgress = True
AddHandler worker.DoWork, Function(sender, e)
' pretend we have a collection of items to process
Dim items(999) As Integer
items.WithProgressReporting(Function(progress) worker.ReportProgress(progress)).ForEach(Function(item) Thread.Sleep(10)) ' simulate some real work
End FunctionAddHandler worker.ProgressChanged, Function(sender, e) ' make sure the figure is written to the ' same point on screen each time Console.SetCursorPosition(1, 0) Console.Write(e.ProgressPercentage) End Function worker.RunWorkerAsync() Console.Read()
End Sub
Unfortunately in VB the line
items.WithProgressReporting(Function(progress) worker.ReportProgress(progress).ForEach(Function(item) Thread.Sleep(10)))
throws an exception "Expression does not produce a value" at the underlined place. There's no such exception in C# where the test code compiles and executes fine. Having to implement the technique into my VB application, I'd like to understand where the problem arises. Could anyone of you tell me what's wrong in the (automatic) translation of the Lambda expression? Thank you Mick
In VB, a function that returns void is a "Sub". This is true with lambda function as well. So your ForEach lambda should be
ForEach(Sub(item) Thread.Sleep(10))
-
In VB, a function that returns void is a "Sub". This is true with lambda function as well. So your ForEach lambda should be
ForEach(Sub(item) Thread.Sleep(10))
Only true with 2010 though, as there is many time I would loved to of used it in my current project that is 3.5 framework
Lobster Thermidor aux crevettes with a Mornay sauce, served in a Provençale manner with shallots and aubergines, garnished with truffle pate, brandy and a fried egg on top and Spam - Monty Python Spam Sketch
-
VB2010 has introduced sub(parameter) into the lambda specification. I haven't tested it but wouldn't the following work?
items.WithProgressReporting(sub(progress) worker.ReportProgress(progress) end sub).forEach(function(item) thread.Sleep(10)))
Lobster Thermidor aux crevettes with a Mornay sauce, served in a Provençale manner with shallots and aubergines, garnished with truffle pate, brandy and a fried egg on top and Spam - Monty Python Spam Sketch
Hi Simon, sorry for the late response which was due to a short holiday of mine. Thanks for your hint which pushed me in the right direction: In the end, all I had to do was change "function" into "sub" in VB. It's finally solved now, and the line
items.WithProgressReporting(Sub(progress) worker.ReportProgress(progress)).ForEach(Sub(item) Thread.Sleep(10))
works, as well as Estys suggestion to factor out the subs. No "end" needed here. Regards - Mick
-
Hi Simon, sorry for the late response which was due to a short holiday of mine. Thanks for your hint which pushed me in the right direction: In the end, all I had to do was change "function" into "sub" in VB. It's finally solved now, and the line
items.WithProgressReporting(Sub(progress) worker.ReportProgress(progress)).ForEach(Sub(item) Thread.Sleep(10))
works, as well as Estys suggestion to factor out the subs. No "end" needed here. Regards - Mick
Glad it helped :thumbsup:
Lobster Thermidor aux crevettes with a Mornay sauce, served in a Provençale manner with shallots and aubergines, garnished with truffle pate, brandy and a fried egg on top and Spam - Monty Python Spam Sketch
-
Try changing this line:
items.WithProgressReporting(Function(progress)
worker.ReportProgress(progress)).ForEach(Function(item) Thread.Sleep(10)) ' simulate some real workTo this:
items.WithProgressReporting(Function(progress) _
worker.ReportProgress(progress)).ToList.ForEach(Function(item) Thread.Sleep(10)) ' simulate some real workThe .ForEach extension method doesn't work with IEnumerables and since that's what WithProgressReporting returns, the resultset must first be cast as a Generic List. Also, I don't know for sure, but it looks like the converter inserted an extra line break. That's why I added the underscore to the end of the first line.
Hi Member... ;) , sorry for the late response which was due to a short holiday of mine. Thanks for your hint which unfortunately didn't work: In the end, all I had to do was change "function" into "sub" in VB. It's finally solved now, and the line
items.WithProgressReporting(Sub(progress) worker.ReportProgress(progress)).ForEach(Sub(item) Thread.Sleep(10))
works, as well as Estys suggestion to factor out the subs (no "end" or "ToList" constructions needed). Regards - Mick
-
I always have trouble with anonymous delegates in VB so I factored them out :
Class Program
Shared worker As BackgroundWorker
Public Shared Sub Main() 'ByVal args As String())
worker = New BackgroundWorker()
worker.WorkerReportsProgress = True
AddHandler worker.DoWork, AddressOf DoWork
AddHandler worker.ProgressChanged, AddressOf ProgressChanged
worker.RunWorkerAsync()
Console.Read()
End SubPrivate Shared Sub DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Dim items = Enumerable.Range(1, 1000) items.WithProgressReporting(AddressOf ReportProgress).ForEach(AddressOf DoSleep) End Sub Private Shared Sub ReportProgress(ByVal progress As Integer) worker.ReportProgress(progress) End Sub Private Shared Sub DoSleep(ByVal item As Integer) Thread.Sleep(10) End Sub Private Shared Sub ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Console.SetCursorPosition(1, 0) Console.Write(e.ProgressPercentage) End Sub
End Class
Cheers
Hi Estys, sorry for the late response which was due to a short holiday of mine. Thanks for your hint which, together with the other guys' ideas, pushed me in the right direction: In the end, all I had to do was change "function" into "sub" in VB. It's finally solved now, and the line
items.WithProgressReporting(Sub(progress) worker.ReportProgress(progress)).ForEach(Sub(item) Thread.Sleep(10))
works, as well as your suggestion to factor out the subs. Just to complete: In your snippet I had to change the definition of 'items' to:
Dim items As IEnumerable(Of Integer) = Enumerable.Range(1, 1000)
in VB. But the most important thing: It works - and I hope I understand it a little better ;) Thanks again, regards - Mick
-
In VB, a function that returns void is a "Sub". This is true with lambda function as well. So your ForEach lambda should be
ForEach(Sub(item) Thread.Sleep(10))
Hi David, sorry for the late response which was due to a short holiday of mine. Thanks for your hint which pushed me in the right direction: In the end, all I had to do was simply change "function" into "sub" in VB. It's finally solved now, and the line
items.WithProgressReporting(Sub(progress) worker.ReportProgress(progress)).ForEach(Sub(item) Thread.Sleep(10))
works, as well as Estys suggestion to factor out the subs (slightly changed). Thanks again, regards - Mick
-
Hi Estys, sorry for the late response which was due to a short holiday of mine. Thanks for your hint which, together with the other guys' ideas, pushed me in the right direction: In the end, all I had to do was change "function" into "sub" in VB. It's finally solved now, and the line
items.WithProgressReporting(Sub(progress) worker.ReportProgress(progress)).ForEach(Sub(item) Thread.Sleep(10))
works, as well as your suggestion to factor out the subs. Just to complete: In your snippet I had to change the definition of 'items' to:
Dim items As IEnumerable(Of Integer) = Enumerable.Range(1, 1000)
in VB. But the most important thing: It works - and I hope I understand it a little better ;) Thanks again, regards - Mick