VB.NET – Is It Acceptable to Define a Module and Class Within a Single .VB Element?

object-oriented-designvb.netvisual studio

Experiment:

I have found it is possible to define both a "Module" (Namespace?) and a "Class" (Namespace?) within a single .Vb element (Module??).

You can try this at home:

  • Create a new Console Application Project.
    *A new .Vb element named "Module1.Vb" is automatically added to the project.
  • Add a new Class .Vb element by right-clicking on the project in Solution Explorer>Add>Class…
  • Give the new class the name Test.
  • View the code for "Test.Vb" and paste in the following:
Imports System.Runtime.CompilerServices


Module ExtensionsTest
    <Extension()>
    Public Sub ToConsole(ByVal Ex As Exception)
        Dim ForeColor As ConsoleColor
        Console.ForegroundColor = ConsoleColor.Red
        Console.WriteLine()
        Console.WriteLine("An unhandled exception has occurred!")
        Console.WriteLine(Ex.ToString)
        Console.ForegroundColor = ForeColor
    End Sub
End Module


Class Test
    Public Sub Test()
        Try
            Dim test As New Object
            test.SomeMethodDoesntExist()
        Catch ex As Exception
            ex.ToConsole()
        End Try
    End Sub
End Class

View the Code for Module 1 and paste in the following:

Module Module1
    Sub Main()
        Try
            Dim tester As New Test
            tester.Test()
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Sub
End Module

Now go ahead and step through or run the application. You'll see it all works. So, let's move on to the…


Meat of the question

Is this acceptable practice?
It may be technically possible – but is it a bad solution for reasons I don't know? (I'm a Mort and really don't want pick up bad coding practices unwittingly)

I originally had this as a Private method within the class definition like this:

Imports System.Runtime.CompilerServices
Class Test
    Public Sub Test()
        Try
            Dim test As New Object
            test.SomeMethodDoesntExist()
        Catch ex As Exception
            ToConsole(ex)
        End Try
    End Sub

    Private Sub ToConsole(ByVal Ex As Exception)
        Dim ForeColor As ConsoleColor
        Console.ForegroundColor = ConsoleColor.Red
        Console.WriteLine()
        Console.WriteLine("An unhandled exception has occurred!")
        Console.WriteLine(Ex.ToString)
        Console.ForegroundColor = ForeColor
    End Sub
End Class

I decided it would be cleaner to define the ToConsole sub as an extension method for Exception objects, but that's where I ran into trouble. When I created the Extension attribute within the Class namespace, I got a compiler error:

Extension methods can be defined only in modules.

So, I tried the above experiment and I declared a Module within the same .VB element where my Class is defined.
As the experiment above shows, this all compiles fine and works as expected, but I'd like to know if this is a good idea or not, and why?

Thanks for taking any time to read this and even more thanks for any time taken to comment or answer!

Best Answer

In general, the idea of one Class or Module per file is something I first noticed in Java (I believe it is/was a requirement there). C# has continued this as a suggestion, and VB.NET probably now has the same suggestion somewhere.

However, as the VB.NET designers decided you can only have extension methods in Modules, you've provided an example where it makes sense for another unit of code to be so closely related to another Class as to include it in the same file.

Of course, with the concept of Partial classes and modules you have the opposite idea of splitting single units across multiple files available too.

And BTW this concept normally means your Module would be named TestExtensions :-)

To your "Namespace?" notes in your question: VB.NET provides a Project-based namespace for your Modules and Classes, so your classes are now named ProjectNamespace.UnitName. If you provided a

Namespace SomeNamespace
...
End Namespace

the enclosed units would be named ProjectNamespace.SomeNamespace.UnitName.

You can have multiple Namespaces in a file too, and you can override the ProjectNamespace with Global.:

Namespace Global.TopLevelNamespace
...
End Namespace

Rereading your question and noting the "(Module?)" note as well, I'm guessing you're actually asking what is the "formal" VB.NET term for code units that include Class and Module and the similar term for a file of code. Because the .NET Module is so often equivalent to an Assembly, most people would know what you meant if you referred to "Namespace-level" code units as "modules", and source files are just "files". (There may be other places that give alternatve names, but I've based this on Microsoft's Introduction.)

Related Topic