Accessing shared class members via an instance and why this is not a good idea.

Accessing shared class members via an instance and why this is not a good idea.

 

Let’s consider this code:

 

Module Module1

    Sub Main()

        Dim x As New C1

        Dim z As Integer

        z = x.SharedVariable

        Console.WriteLine(z)

    End Sub

End Module

Class C1

    Public Shared SharedVariable As Integer = 1

End Class

“There is nothing wrong” you would say. We get x.SharedVariable and print it out. But this is not entirely correct. The tricky part is the way we are using x here.

Strictly speaking shared members do not belong to a particular instance. They are part of the type itself and belong to the type that defines them. Unlike instance fields that have a separate copy for each instance, the shared field has only one copy and it is attached to the class itself.

It would be more expressive if we get the SharedVariable from C1 directly:

C1.SharedVariable

In fact internally compiler does exactly that. It replaces x with its type and x.SharedVariable becomes C1.SharedVariable

Now let’s check this code:

Module Module1

    Sub Main()

        Dim x As New C1

        Dim y As New C2

        Dim z As Integer = y.WriteHelloGetC1Inst.SharedVariable

        Console.WriteLine(z)

    End Sub

End Module

Class C1

    Public Shared SharedVariable As Integer = 1

End Class

Class C2

    Public Function WriteHelloGetC1Inst() As C1

        Console.WriteLine("hello")

        Return New C1

    End Function

End Class

Would you expect to see “hello” on the console when you get y.WriteHelloGetC1.SharedVariable?

Rriiiight. You will not. Compiler will replace whole y.WriteHelloGetC1Inst with C1 and you will get this instead:

C1.SharedVariable

Pretty sneaky. Actually anything like <huge_expression_returning_C1_instance>.SharedVariable will be understood by the compiler as just C1.SharedVariable without going through trouble of evaluating <huge_expression_returning_C1_instance>.

It seems that it would be much better if you write just C1.SharedVariable to not make an impression that something else is called.

Actually in the next version of VB.Net compiler politely warns you against using misleading syntax:

Module1.vb(6) : warning BC42025: Access of shared member through instance variable. Preceding expression will not be evaluated.