2

I have this weird behavior in VB.Net I am stuck with. At the moment I am not able to determine whether I am missing some concept or if it is a bug.

I have a base class:

Public MustInherit Class BaseType(Of T As BaseType(Of T)) :
    Implements IEquatable(Of BaseType(Of T))
    Protected Sub New(key As Integer, value As List(Of String))
        LogManager.GetLogger("INFO").Info("Strings: " & vbTab & value.Count())
        If key <> -1 Then
            enumValues.Add(CType(Me, T))
        End If
    End Sub

    Protected Shared Function TypeFromStringBase(name As String) As T
        For Each b As T In enumValues
            LogManager.GetLogger("DEBUG").Info(b.Names(0))
            If b.Names.Contains(name) Then
                Return b
            End If
        Next

        Return TypeFromStringBase("Keine")
    End Function
End Class

And a Class that inherits it:

Public Class AnschlussType : Inherits BaseType(Of AnschlussType) :
    Implements IEquatable(Of AnschlussType)
    Public Shared ReadOnly Rund As New AnschlussType(1, {"Rund", "1"})
    Public Shared ReadOnly Flach As New AnschlussType(2, {"Flach", "2"})
    Public Shared ReadOnly Gewinde As New AnschlussType(3, {"Gewinde", "3"})
    Public Shared ReadOnly Kein As New AnschlussType(4, {"Kein", "None", "4"})

    Private Sub New(key As Integer, names As String())
        MyBase.New(key, names.ToList())
    End Sub

    Public Shared Function TypeFromString(name As String) As AnschlussType
        Return TypeFromStringBase(name)
    End Function
End Class

Here is the weird part I don't get. The first time you call AnschlussType.TypeFromString("Some String"), VB should create all the Public Shared ReadOnly members. This results in four calls to BaseType.New. Each of those calls then adds its own type to the enumValues List.

After all those initializations, finally, the AnschlussType.TypeFromString call will be executed. There it calls TypeFromStringBase which iterates over the enumValues List we filled right before.

This all works fine in the DEBUG mode.

Here is the weird part I don't get. Now I tried RELEASE mode. The enumValues.Count would always stay 0. I assumed this because the logger does not print anything, which means it doesn't iterate, which means it is zero. So I investigated a little more and put a logging statement into BaseType.New. And this does NOT log at all. This leads me to the conclusion that New is not executed at all.

Let me emphasize that this all works great in DEBUG mode and with other subtypes that have Public Shared ReadOnly members in the same matter. But this does not work in RELEASE mode.

Does anyone have a hint for me what I could be missing?

Appulus
  • 18,630
  • 11
  • 38
  • 46
Yatekii
  • 77
  • 9
  • Is this Logmanager called Log4Net? I've not worked with it, but this may help, http://stackoverflow.com/questions/22490447/log4net-doesn-t-write-log-in-release-mode-console-application Also, you can add the tag for the log manager if it's [tag:log4net] and may get additional help. – Jimmy Smith Jul 20 '16 at 14:37
  • You cannot expect this to work when you can call TypeFromStringBase() without ever creating a concrete instance of AnschlussType. The egg has to go before the chicken. – Hans Passant Jul 20 '16 at 16:02
  • With all other Types this exact code works. So it's neither the logger (because it works perfectly fine in DEBUG mode (It is the default .NET logger)) nor the hen-egg problem (This should work fine since it's a shared class of which I expect the ctor to be executed at the start of the program (even if it shouldn't, why does it work in 100% of the cases in DEBUG?)). edit: I can see now that the hen-egg problem could exist, I will think a little more about it tomorrw. The main DEBUG/RELEASE question still stands. – Yatekii Jul 20 '16 at 19:02

1 Answers1

0

If a static constructor (Section 10.11) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.

Assuming VB works like C#, your shared (i.e. static) fields aren't being initialized because you haven't used them.

Try creating a shared constructor.

Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
  • Well I too assume it's the same as in C#. Doesn't it have a default ctor? Also: why would it work in DEBUG mode but not in RELEASE? And as we just found out: It works too if we deploy it. I will try your suggestion tomorrow. – Yatekii Jul 20 '16 at 19:03
  • DEBUG mode turns off a lot of optimizations. Running inside the debugger can also change the way the code is interpreted. I'm guessing that could be the cause, but I don't know the implementation details. – Jonathan Allen Jul 21 '16 at 03:58