-1

I'm extending a .NET 3.5 application with foundations laid by someone else and there are member variables added to namespace My:

Namespace My
    Private connection As SqlClient.SqlConnection
    Friend appSession As SomeCustomNamespace.clsSession
    ' and a few more others...
End Namepace

I'm having some form and doing processing there. If I run the code in standard way (OnClick...) both member vars have their values. If I move the same code to BackgroundWorker and launch via RunWorkerAsync(), first variable has value but the second is Nothing (null).

What is causing the problem? How to correct or workaround this? (My.Application.appSession must be set because many methods refer to it.)

(Is there a chance to use background worker jobs in application which uses such an implementation of globals?)

miroxlav
  • 11,796
  • 5
  • 58
  • 99
  • Could you provide more detail like can you use Dot Net 4.0 or higher and perhaps elaborate a bit more with the code. If you use 4.0 or higher use Tasks instead of the Background worker. – jcwrequests Sep 20 '13 at 22:52
  • For some time I have to stay and .NET 3.5. I know Tasks exist and maybe this will be the way once I migrate. Is there a solution for .NET 3.5? What can cause the strange behavior I observe? – miroxlav Sep 20 '13 at 23:06
  • @jcwrequests I have done testing using the same simple code in both threads and the results are as seen in question. – miroxlav Sep 20 '13 at 23:24
  • I can suggest this assume free reference that I believe can help http://www.albahari.com/threading/. It provides a lot of excellent information that you can quickly read to get a better understanding on how to work with threads. If you could provide a more detailed code example perhaps put something up on gist.github.com I would certainly be willing help. – jcwrequests Sep 20 '13 at 23:42
  • @jcwrequests Great resource, I appreciate it. OK, based on trivial test project I have found out that the variable is stored on stack and new thread gets its own stack. Putting variable on heap by making it `shared` solved the problem (in test project) although ton of warnings came that for shared member, qualifying expression (i.e. `My.Application`) won't be evaluated. I'm not sure if I can afford `shared` members in our real application, I will need to verify. Best way would be copying content of original `My.Application` into new thread. – miroxlav Sep 21 '13 at 00:38
  • @jcwrequests I posted the whole solution I developed after some research. Hopefully this initialization issue was the only problem with separate thread (in case of this application). I'm really not sure if this StackOverflow question was worthless as someone has downvoted it in the meantime... – miroxlav Sep 23 '13 at 13:06

1 Answers1

0

After some research I decided to pass My.Application as argument to BackgroundWorker.Run() and in BackgroundWorker_DoWork() perform shallow copy of received parameter back to My.Application. Thus I got the content of My.Application back.

Private Sub StartBackgroundWork() 
    Me.BackgroundWorker.RunWorkerAsync(My.Application)
End Sub

Private Sub BackgroundWorker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) _
        Handles BackgroundWorker.DoWork

    My.Application.ShallowCopyFrom(e.Argument)

    'start work here...
End Sub

and ShallowCopyFrom() method I created based on this StackOverflow answer. In VB, it must be put into code module (use Add Module... command, not Add Class...):

Imports System.Reflection

Module CompilerExtensionsModule

<System.Runtime.CompilerServices.Extension> _
<System.ComponentModel.Description("Performs shallow copy of fields of given object into this object based on mathing field names.")> _
Public Sub ShallowCopyFrom(Of T1 As Class, T2 As Class)(ByRef obj As T1, ByRef otherObject As T2)
    Dim srcProps As Reflection.PropertyInfo() =
        otherObject.[GetType]().GetProperties(Reflection.BindingFlags.Instance Or Reflection.BindingFlags.[Public] Or Reflection.BindingFlags.GetProperty)

    Dim destProps As Reflection.PropertyInfo() =
        obj.[GetType]().GetProperties(Reflection.BindingFlags.Instance Or Reflection.BindingFlags.[Public] Or Reflection.BindingFlags.SetProperty)

    For Each [property] As Reflection.PropertyInfo In srcProps
        Dim dest = destProps.FirstOrDefault(Function(x) x.Name = [property].Name)
        If Not (dest Is Nothing) AndAlso dest.CanWrite Then
            dest.SetValue(obj, [property].GetValue(otherObject, Nothing), Nothing)
        End If
    Next

    Dim srcFields As Reflection.FieldInfo() =
        otherObject.[GetType]().GetFields(Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Public)

    Dim destFields As Reflection.FieldInfo() =
        obj.[GetType]().GetFields(Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Public)

    For Each [field] As Reflection.FieldInfo In srcFields
        Dim dest = destFields.FirstOrDefault(Function(x) x.Name = [field].Name)
        If Not (dest Is Nothing) Then
            dest.SetValue(obj, [field].GetValue(otherObject))
        End If
    Next

End Sub

End Module
Community
  • 1
  • 1
miroxlav
  • 11,796
  • 5
  • 58
  • 99