Why does continueWith uses action(of task) as a parameter? - vb.net

Basically, it asks for a sub with Task as a parameter. That's what Action(of Task) right?
Why?
I know I can pass normal sub to continueWith. I never remember passing a sub that requires a task parameter.

It is by the definition. 'ContinueWith' should in most cases operate with the result of 'antecedent' task. If you forget how to call 'ContinueWith', Visual Studio 'Peek Definition' will help you. So, right clicking on 'ContinueWith' and by choosing 'Peek Definition' you will examine the signature. Basically, it looks like is shown in the snippet below.
public Task<TNewResult> ContinueWith<TNewResult>(
Func<Task<TResult>, TNewResult> continuationFunction)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return this.ContinueWith<TNewResult>(continuationFunction, TaskScheduler.Current, new CancellationToken(), TaskContinuationOptions.None, ref stackMark);
}
If it is too complicated, you can use a snippet and save an example and then inserted when you need it.
So, let's create an example.
Module Module1
Sub Main()
Dim taskA As Task(Of DayOfWeek) = Task.Run(Function() DateTime.Today.DayOfWeek )
' Execute the continuation when the antecedent finishes.
Dim taskB As Task(Of string) = taskA.ContinueWith(Function (antecedent)
Return $"Today is {antecedent.Result}"
End Function)
taskb.Wait()
Console.WriteLine(taskB.Result)
Console.ReadLine()
End Sub
End Module

Related

vb.net Async I just don't get it

Public Function PiesTableTest(compairFile As String, version1 As String, Optional silent As Boolean = False) As Boolean
Dim dpgs As New frmDetailProgress
Dim retturn As Boolean
PiesThreadedTableTest(compairFile, version1, silent, dpgs)
End Function
Async Function PiesThreadedTableTest(compairFile As String, version1 As String, silent As Boolean, dpgs As frmDetailProgress) As Task(Of Boolean)
Dim ctl() As xmlControlAry
Dim xmlDoc As XElement
Dim xmlNodes As IEnumerable(Of XElement)
Dim notfound(0) As String
version = version1
nodeErrors = False
If Not silent Then
dpgs.lblTital.Text = "Pies Configuration Check"
dpgs.add("Pies Version = " & version)
dpgs.add("Loading Config Data....")
dpgs.Show()
End If
' load configuration data
GetPiesControl(ctl, version)
' load test xml file
xmlDoc = XElement.Load(compairFile)
xmlNodes = xmlDoc.Elements()
For Each ele As XElement In xmlNodes
NodeDrill("", ele, ctl, dpgs, notfound, silent)
Next
If nodeErrors And Not silent Then
dpgs.add("Testing done with Errors!!!", "R")
Else
dpgs.add("Testing Done NO ERRORS!", "G")
End If
Application.DoEvents()
If silent Then
dpgs.Dispose()
End If
'PiesThreadedTableTest = Not nodeErrors
If nodeErrors Then
Return False
Else
Return True
End If
End Function
I am trying to understand multi threading. frmDetailProgress is a "please wait " kind of form. and i have a animated gif on it. Plus it has a check box to close automatically after completion. Well the form is frozen till the process is done. I am trying to get the piesthreadedtabletest to run in another thread. I have read allot on this but i just don't understand the concept. I don't understand the await function enough to make this work. i get that await is designed to stop processing until something happens. But i want that form freed up to work. I get an error saying that the function will run synchronously unless i have an await - Why?
I got it working. It was a lack of understanding and i probably still need to learn more. I hope this will help someone in the future.
i created a class to call functions in the other class running in the second thread.
imports system.threading
public sub callThreadedProcedure()
dim tp as system.threading.thread ' this will be for the object running in the other thread
dim objectToRun as myclass ' this is the object you want to run in the thread
'this gets the object and puts it into the new thread
tp = new thread(sub() objectToRun.FunctionToRun(<put your parameters here if any>))
' start execution of the object in a new thread.
tp.start()
' that will get it to run in a separate thread. It works, there might be a better way
' and might not work in all situations, but for now it fixed my problem.
end sub
if you are trying to run functions in the original thread you need to pass a
reference to that object to the one in the second thread. you must then use invoke to run a function or sub from the second thread.
Invoke(sub() obj.function(<parameters>))
thanks Idle_mind invoked worked like it should.
I appreciate all that helped me along.

A few simple questions about functions that have no references being greyed out in visual studio 2019?

Not everything though
Public Shared Async Function getMarketDetailFromAllExchangesAsync() As Task
Dim taskList = New List(Of Task)
Dim starttime = jsonHelper.currentTimeStamp
LogEvents("Start Getting Market Detail of All")
For Each account In uniqueAccounts().Values
Dim newtask = account.getMarketInfoAsync().ContinueWith(Sub() account.LogFinishTask(MethodBase.GetCurrentMethod().Name, starttime))
taskList.Add(newtask)
'newtask.ContinueWith(Sub() LogEvents(account.ToString))
Next
Await Task.WhenAll(taskList.ToArray)
Dim b = 1
'Await getPairsPriceStepForAllAccountsAsync()
End Function
Private Shared Async Function getPairsPriceStepForAllAccountsAsync() As Task
For Each account In uniqueAccounts()
Await account.Value.getPairsPriceStepAsync()
Next
End Function
getPairsPriceStepForAllAccountsAsync is greyed out. I know it's because it has no reference and can be deleted safely. However, the function getMarketDetailFromAllExchangesAsync also have 0 references and it's black.
I wonder why?
Both can be commented out safely.
I wonder if I can easily found such functions too
It is because one is Private and one is Public. A Private method not called within the same class is guaranteed not to be called anywhere, while a Public method could be called in some other non-accessible code.

Ensure maintainability & testability in file-processing application

Problem
I want to refactor an old application which has grown over time and is awful to maintain/test. Basically the app needs to read an file an process it lines.
The file to be read can be compared to a CSV-file, where the first field determines the type of the line, something like this:
1,abcd,...
1,3423,...
2,"abc",...
5,test,...
Currently the application works like this (pseudo-code):
For Each line in file.getLines()
if (line.StartsWith("1,") then
' Process line of type 1
elseif (line.StartsWith("2,") then
' Process line of type 2
...
End If
Next
This obviously is a nightmare to maintain and test. Therefore I'd like refactor this whole thing and thought of doing it like this:
Create a parser for each line-type
Let each parser register itself to a handler, which will raise an event for each line
Code Idea
Handler:
Public Class ParserHandler
Public Event Parse(RepLine As ReportLine)
Public Event FileFinished()
Public Sub RaiseParse(RepLine As ReportLine)
RaiseEvent Parse(RepLine)
End Sub
Public Sub RaiseFileFinished()
RaiseEvent FileFinished()
End Sub
End Class
Parser:
Public Class FirstParser
Public Sub New(Handler As ParserHandler)
AddHandler Handler.Parse, AddressOf Parse
AddHandler Handler.FileFinished, AddressOf FileFinished
End Sub
Public Sub Parse(RepLine As ReportLine)
If Not RepLine.Type = 1 Then
Return
End If
' Process
End Sub
Private Sub FileFinished()
' Final stuff, eg. insert into DB
End Sub
End Class
Main:
Dim ParserHandler As New ParserHandler()
Dim FirstParser As New FirstParser(ParserHandler)
Dim SecondParser As New SecondParser(ParserHandler)
...
For Each line in file.getLines()
' Extract Id and construct ReportLine-object here
ParserHandler.RaiseParse(ReportLine)
Next
I think this looks way better than the original version, but I'm still not convinced that this is really the way to go. In case of testing the parsers with unit tests, I still have to create a handler first. This might be ok, but feels wrong as the parser should be testable separately (is it wrong?).
I like the use of events in this case, as not every parser needs to implement every possible event of the handler, which prevents me from just having an IParser interface.
What do you think of this approach, is it good to go? Are there any best practices/design pattern I should look into for a clean solution to this problem?

Assigning a reference type object a value on a secondary thread, and then working with this object from my primary thread

I am trying to create a variable which is of type MyReferenceTypeObject and of value null on thread one, use a delegate to make this thread equal to a new instance of MyReferenceTypeObject on thread two, and then access members of MyReferenceTypeObject back on thread one (in the delegates callback method).
My code is below:
Module Module1
Delegate Sub EditReferenceTypePropertyDelegate(ByVal referenceTypeObject As MyReferenceTypeObject, ByVal numberToChangeTo As Integer)
Sub Main()
Dim editReferenceDelegate = New EditReferenceTypePropertyDelegate(AddressOf EditReferenceTypeProperty)
Dim newReferenceTypeObject As MyReferenceTypeObject
editReferenceDelegate.BeginInvoke(newReferenceTypeObject, 2, AddressOf EditReferenceCallback, newReferenceTypeObject)
Console.ReadLine()
End Sub
Sub EditReferenceTypeProperty(ByVal referenceTypeObject As MyReferenceTypeObject, ByVal numberToChangeTo As Integer)
referenceTypeObject = New MyReferenceTypeObject()
referenceTypeObject.i = numberToChangeTo
End Sub
Sub EditReferenceCallback(ByVal e As IAsyncResult)
Dim referenceObject = DirectCast(e.AsyncState, MyReferenceTypeObject)
Console.WriteLine(referenceObject)
End Sub
End Module
Class MyReferenceTypeObject
Public Property i As Integer
End Class
However, newReferenceTypeObject comes into my callback method as null. I think I understand why, but the problem is that I need to pull some data from a database which I then need to pass into the constructor of newReferenceTypeObject, this takes a couple of seconds, and I don't want to lock up my UI while this is happening. I want to create a field of type MyReferenceTypeObject on thread one, instantiate this on thread two (after I have pulled the data of the database to pass into the constructor) and then work with members of the object back on thread one once the instantiation is complete.
Is this possible? I am using VB.Net with .Net 4.0 on Visual Studio 2012.
If you want to keep the GUI responsive during a long running action, I'd consider using the Task<> library (Comes with .NET 4.0). Here's a quick example.
Sub Main()
Dim instantiateTask = New Task(Of MyReferenceTypeObject)(Function()
' Call your database to pull the instantiation data.
Return New MyReferenceTypeObject With {.i = 2}
End Function)
instantiateTask.Start() ' Start the task -> invokes a ThreadPool.Thread to do the work.
instantiateTask.ContinueWith(Sub(x)
Console.WriteLine(x.Result.I)
End Sub, TaskScheduler.FromCurrentSynchronizationContext())
End Sub
.Wait blocks the GUI thread. However, you could use ContinueWith which is async and therefor nonblocking. Also you need to provide the TaskScheduler ( TaskScheduler.FromCurrentSynchronizationContext ) from the GUI thread to prevent cross-thread exceptions in case you want to update the UI from within the async method.

How to mock a method (custom behavior) with Rhino Mocks in VB.NET

How can I mock one method with RhinoMocks in VB.Net? The reference I found is in C#:
Expect.Call(delegate{list.Add(0);}).IgnoreArguments()
.Do((Action<int>)delegate(int item) {
if (item < 0) throw new ArgumentOutOfRangeException();
});
SharpDevelop converts this to:
Expect.Call(Function() Do
list.Add(0)
End Function).IgnoreArguments().Do(DirectCast(Function(item As Integer) Do
If item < 0 Then
Throw New ArgumentOutOfRangeException()
End If
End Function, Action(Of Integer)))
But that doesn't work either (it doesn't compile).
This is what I want to do: create a new object and call a method which sets some properties of that method. In real-life this method, will populate the properties with values found in the database. In test, I would like to mock this method with a custom method/delegate so that I can set the properties myself (without going to the database).
In pseudo-code, this is what I'm trying to do:
Dim _lookup As LookUp = MockRepository.GenerateMock(Of LookUp)()
_luvalue.Expect(Function(l As LookUp) l.GetLookUpByName("test")).Do(Function(l As LookUp) l.Property = "value")
Unfortunately you're attempting to do both a Sub lambda and a Statement Lambda. Neither are supported in VS2008 (but will be in the upcoming version of VS). Here is the expanded version that will work for VB
I'm guessing at the type of m_list
Class MockHelper
Dim m_list as new List(Of Object)
Public Sub New()
Expect(AddressOf CallHelper).IgnoreArguments().Do(AddressOf Do Hepler)
End Sub
Private Sub CallHelper()
m_list.Add(0)
End Sub
Private Sub DoHelper(ByVal item as Integer)
if item < 0 Then
Throw New ArgumentOutOfRangeException
End If
End Sub
End Class
I have never mocked something w/ both a delegate and a lambda so I can't give a full solution to this problem, but I did want to share some example code for the usual "AssertWasCalled" function in Rhino Mocks 3.5 for vb developers because I spent some time trying to grok this... (keep in mind the below is kept simple for brevity)
This is the method under test - might be found inside a service class for the user object
Public Sub DeleteUserByID(ByVal id As Integer) Implements Interfaces.IUserService.DeleteUserByID
mRepository.DeleteUserByID(id)
End Sub
This is the interactive test to assert the repository method gets called
<TestMethod()> _
Public Sub Should_Call_Into_Repository_For_DeleteProjectById()
Dim Repository As IUserRepository = MockRepository.GenerateStub(Of IUserRepository)()
Dim Service As IUserService = New UserService(Repository)
Service.DeleteUserByID(Nothing)
Repository.AssertWasCalled(Function(x) Wrap_DeleteUserByID(x))
End Sub
This is the wrap function used to ensure this works w/ vb
Function Wrap_DeleteUserByID(ByVal Repository As IUserRepository) As Object
Repository.DeleteUserByID(Nothing)
Return Nothing
End Function
I found this to be a very nasty solution, but if it helps someone w/ the same issues I had it was worth the time it took to post this ;)