Search code examples
vb.netwinformsinitializecomponent

Clean elegant solution to form-class level component collection initializing before Initialize Component?


I am converting an old Vb6 solution to .net 2.0 in vs2010. I've been working in C# for about 3 years now and .net for 5. I don't recall having this problem in C#, but if I want initialize a readonly collection of DerivedControlFoo Is there a clean way to do it besides creating a sub to do it all off somewhere else? I'd love to be able to do it at the class level at the declaration for readability and simplicity.

Example:

Private _formattedFormulaText As IEnumerable(Of Label) = New List(Of Label) From { _
 FormulaLabels0, FormulaLabels1, lblBrownFormula, FormulaLabels3, lblGreenFormula, _
      lblOrangeFormula, lblRedFormula, FormulaLabels7, lblFormulaTotal}

Doing it the straightforward easy way, results in the collection being filled with {nothing,..,nothing}


Solution

  • This is not thread safe, but works very well for my purposes:

    Solution in use:

     Private _formattedFormulaText As New Lazy(Of IEnumerable(Of Label))(Function() New List(Of Label) From { _
     FormulaLabels0, FormulaLabels1, lblBrownFormula, FormulaLabels3, lblGreenFormula, _
          lblOrangeFormula, lblSRedFormula, FormulaLabels7, lblFormulaTotal})
    

    drawbacks - all code touching the variable has to add an accessor .value. My code has 5 of these lazy collections and 1-2 touchpoints per collection usually in the same function.

    Drawback illustration:

    Dim clearText = Sub(c As Control) c.Text = String.Empty
            _formattedFormulaText.ToList.ForEach(clearText)
    

    becomes

    Dim clearText = Sub(c As Control) c.Text = String.Empty
            _formattedFormulaText.Value.ToList.ForEach(clearText)
    

    Not compliant with good practices for debugger display used in .net 4, but would be easy to add in using reflector


    Please note a property could have been used to eliminate the need to .value in the touchpoints:

       Private ReadOnly Property FormattedText As IEnumerable(Of Label)
            Get
                Return _formattedFormulaText.Value
            End Get
        End Property
    

    supporting class:

    ''' <summary>
    ''' translated from http://msdn.microsoft.com/en-us/vcsharp/bb870976.aspx
    ''' </summary>
    Public Class Lazy(Of T)
        Private _func As Func(Of T)
        Private _result As T
        Private _hasValue As Boolean
        Public Sub New(ByVal func As Func(Of T))
            _func = func
            _hasValue = False
        End Sub
        Public ReadOnly Property Value As T
            Get
                If Me._hasValue = False Then
                    _result = _func()
                    _hasValue = True
                End If
                Return _result
            End Get
        End Property
    
    End Class
    

    design based on MSDN's article Lazy Computation in C# Also with assistance from Reflector against

    assembly\NativeImages_v4.0.30319_32\mscorlib\246f1a5abb686b9dcdf22d3505b08cea\mscorlib.ni.dll