5

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!

  • 3
    This is a well-written question. – JeffO Jul 15 '15 at 14:45
2

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.)

|improve this answer|||||
  • Mark - saw your edit on my question, how did you get the code block to format without having to type something aside from spaces between the list block and the code block? I couldn't get it to work without typing something there. – CBRF23 Jul 22 '15 at 2:36
  • 1
    If you look at the "side-by-side markdown" diff of my edit you'll see I explicitly told it to format in VB in a comment that also forces it to notice a new code block. – Mark Hurd Jul 22 '15 at 2:39
  • @MarkHurd, Module in vb.net is same things as static class in the C#. In C# extension methods are allowed only in the static classes too. – Fabio Oct 26 '15 at 16:46
  • @Fabio There are differences, but, for the purposes of this question, yes, C# static class for extension methods could be put in the same file as the main class. – Mark Hurd Oct 27 '15 at 0:27
  • Yes, you are right, you can put classes, namespaces in the same file. But I little bid confused about differences of vb.net Modules and C# static classes - on my opinion there are no differences – Fabio Oct 27 '15 at 1:48
2

As you've found out, code works fine regardless of which file you put it in. So it comes down to organization... where will you put things?

What I've found is that any departure from the "standard" conventions makes it very difficult to navigate through a code base of any significant size. You say you have this little helper class, but where the hell is it? You put it in a different solution, and I have a metadata reference to it, but where did you actually put it? Unless you adhere strictly to the one file per class/interface/whatever, you've now forced me to do a search, and I'm coming after you with a carving knife.

This Stack Overflow post lists some of the exceptions where it might make sense to break this rule:

  1. Partial classes,
  2. Extension methods,
  3. Enums that only pertain to a single class, although I still generally put those in their own file.
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.