VB.NET how do I insulate a class from accessing external functions - vb.net

We are working on updating a code project that has become very messy over time. There are lots of modules which contain public functions that can be used from anywhere.
We want to move as much of the code into classes as possible, so that these can eventually be re-used in the next generation of the application. Is there a way that we can prevent these classes from using any (non-system) functions?
Example:
public module annoyingModule
public function addOneAndOne() as int
return 2
end function
.....(load more functions)....
end module
public class pricer
...(class code)...
end class
I want to make sure that nobody on the team can accidentally make a reference to the addOneAndOne function - if they need functionality from a module which is not part of the class, they need to re-implement it inside the new class.

You need to move your new classes to a separate class library project. As long as your new class library project does not reference the old project and does not include a copy of the old modules, all of that stuff will be inaccessible from the classes in that class library project. You then, in the old project, need to add a reference to your new class library project. That way, the old code can use the new classes, but the new classes will not be able to use the old modules.

Related

What is the use of Module in VB.Net programming?

I am creating a .dll for a CAD tool I use.
After creating a new project (class library) , I got a "public class-end class" block.
I wrote my main method inside that block. When I run the dll in my CAD tool, its giving me main entry point missing error.
So i come back and change the "public class-end class" ---> "Public Module-end Module".
Now its able to find the main method.
Why is this so? Ive read on these forums that we should not be using modules as much.
If I were to not use modules so much, how I am supposed to make it work without the module block?
VB.Net doesn't have static classes like C# has. Static classes allow you to create static methods such that
class foo
{
void bar() {}
}
Accessed in VB.Net like this
foo.bar()
If you want to create the same functionality with VB.Net you have two options, which are either using a Module
Module foo1
Sub bar()
End Sub
End Module
Class foo2
Shared Sub bar()
End Sub
End Class
However the difference is how Module and Class are scoped. Modules are globally scoped so you can call the module method outside of the originating namespace without qualifying it with the Module name, but to call the static method you need to qualify it with the class name, and even import the namespace in the case of a class with static method
bar()
foo2.bar()
But what Modules are certainly good for is Extension Methods, and the global scope actually helps here if you want to extend a class across your project
Module Extensions
<Extension>
Sub bar(value As String)
End Sub
End Module
Dim s = "my string"
s.bar()
In your case, it's expecting a C# style static class with method, and since VB.Net doesn't have static classes, a Module or class with static method both satisfy that.
Modules come from legacy versions of Visual Basic and sort of act as the "OG" of Visual Basic code files. When Visual Basic 6 and earlier was around, Visual Basic was sort of quasi object oriented and while classes existed, it made more sense to use modules in lieu of static classes. Then when Visual Basic .NET was introduced, Microsoft made a real effort to make the programming language a true object oriented programming language.
People likely tell you to use classes over modules because modules are holdovers from the days prior to Visual Basic being a pure object oriented language. Starting from 2005 on forward, anything you could do in a module could basically be done as a static (aka shared) only class with the exception of extension methods. So by using classes over modules, you're taking a more .NET oriented approach rather than a Visual Basic first approach.
With regards to your specific problem, the issue is that your CAD tool is looking for an entry method, but cannot find one. The simple solution is to add a shared method:
Public Class MyClass
Public Shared Sub Main()
' ...
End Sub
End Class

References to startup object fail when converting WinForms app to Class Library

I'm trying to convert WinForms app into a class library - long story short the production environment I'm working in will allow our users to make changes to DLLs but not EXEs, so I'm trying to shove an entire existing app into a DLL and then just create and show an instance of the startup object/form from a second WinForms app with the goal of creating some kind of auto-update system.
I've changed the output type of the project to Class Library, added the launcher app, etc, but attempting to build the old app as a class library throws hundreds of errors, almost all of which are Reference to a non-shared member requires an object reference.
Upon inspection, these errors are appearing everywhere in the code that the startup object/form or any of its properties or methods are referenced. Since a great many things in a WinForms application naturally reference the main form... this is problematic.
Stuff like:
If DbConn = n.DbConn_.Prod Then
miParent = mainform.MiProdReq
throws the aforementioned error upon the attempt to access mainform.MiProdReq
Am I missing some simple/obvious step here?
You are referring to the default instance of the mainform type in that code. Default instances are provided by something automagically generated when building Windows Forms Application projects. Class Library projects have no such thing as default instances, so any code that tries to use them will appear to be trying to access instance members as though they were Shared.
You need to put an instance somewhere and change your code to refer to that instead. If you use a global variable, which is not ideal itself but the simplest option for where you're at, then you can just do a Find & Replace In Files to find the references you need to change.
Note that default instances are something that most experienced developers would suggest avoiding anyway. They don't exist in C# and I've never heard complaints about that, so it's hardly onerous. They were added to VB as a convenience for beginners and migrating VB6 developers who weren't used to proper OOP.
EDIT:
I haven't tested it but you may be able to use Application.OpenForms(0) to get a reference to the startup form anywhere in your library. You could, perhaps, add a module like this:
Module Module1
Private _mainform As Form1
Public ReadOnly Property mainform As mainform
Get
If _mainform Is Nothing Then
_mainform = DirectCast(Application.OpenForms(0), mainform)
End If
Return _mainform
End Get
End Property
End Module
and then your code may even just work as it is.

How to hide variables and some functions in a module in vb.net

I am hobby programmar.Now, am in the middle of making a class library in vb.net. I am making some necessary win32 API functions inside a class library and use it in my hobby projects for ease of use.
I have a main class and few modules in this project. For easiness, i made each module for each section. For example a window module for window related api declarations and variables and structure. The main class contains only all the wrapper functions. So i am declared the variables and structures and api declarations as public so that i can access them from main class. After i build this class library, i just tested it. But there is a problem. All public vars and structures and declarations are available to access there in my test project. I need to hide those declarations and structures and special vars. They are for internal use. But how to make them hide ? When i declared them as private, i can't access them from my wrapper function in Mainclass. What to do

VB.NET: Avoiding redundancies

Each of my VB.NET projects needs a certain set of custom modules.
For example:
modLog
modGUID
modControls
modRegistry
In SOME of these modules I have a few references to other modules.
For example the sub modLog.WriteLog goes like this:
Public Sub WriteLog(Byval uText As String)
If globalclassOEM.IsOEMVersion Then
sPath = (some custom path)
Else
sPath = (some default path)
End if
'Write log text to file
End Sub
This is really stupid because sometimes I have to add really many modules and classes to a tiny projects just to solve some dependencies as the above and to be able to use a few modules that I really need.
Is there any best tactics in VB.NET to avoid such situations?
The best way to avoid such problems, would be to avoid that problem ;) Means: Libraries should do exactly what they are meant to do and not do some "extra work" in the backgorund. In your example: Why does the WriteLog function need to determine the path and why doesnt the caller define it and pass it to the logging function/class?
IF you still want or need to have the functions in that way, you might circumvent the problem by defining interfaces and then put ALL your interfaces into a single library, but NOT the classes that implement them. That would still require to load the file with the interface definitions, but of course you don't need to load any class that implements it.
You might also use some kind of plugin system and when your logging class (in this example) is created, it might try to dynamically load the required assemblies. If they do not exit, the class will without them, otherwise it can use them as pretended. Doesnt make programmers life easier, though (imho).
The "best" way (imho again) would be the first suggestion. Dont have "low level" libraries referencing other libraries. Everything else most likely would be considered to be a design flaw and not a "solution".
I have not covered a whole heap of referencing in VB.net, however, would it be possible for you to create a .dll with all the base modules. This would mean you could reference this .dll saving you time. For the extenuating circumstances where you have references to other modules you could just manually write that module.
As others have alluded to, you never want to directly include the same code file in multiple projects. That is almost never a good idea and it always leads to messy code. If you have common code that you want to share between two different projects, then you need to create a third project (a class library) which will contain the common code, and then the other two projects will just reference to the class library. It's best if you can have all three projects in the same solution and then you can use project references. However, if you can't do that, you can still have a direct file reference to the DLL that is output by that class library project.
Secondly, if you really want to avoid spaghetti code, you should seriously look into dependency-injection (DI). The reason I, and others have suggested this, is because, even if you move the common code into class libraries so that it can be shared by multiple projects, you'll still have the problem that your class libraries act as "black-boxes" that magically figure out everything for you and act appropriately in every situation. On the face of it, that sounds like a good thing for which a developer should strive, but in reality, that leads to bad code in the long run.
For instance, what happens when you want to use the same logging class library in 100 different projects and they all need to do logging in slightly different ways. Now, your class library has to magically detect all of those different situations and handle them all. For instance, some projects may need to save the log to a different file name. Some may need to store the log to the Windows event log or a database. Some may need to automatically email a notification when an error is logged. Etc. As you can imagine, as the projects increase and the requirements grow, the logging class library will need to get more and more complex and confusing which will inevitably lead to more bugs.
DI, on the other hand, solves all these issues, and if you adhere to the methodology, it will essentially force you to write reusable code. In simple terms, it just means that all the dependencies of a class should be injected (passed by parameter) into it. In other words, if the Logger class needs an event log, or a database connection, it should not create or reach out and find those things itself. Instead, it should simply require that those dependencies be passed into it (often in the constructor). Your example using DI might look something like this:
Public Interface ILogFilePathFinder
Function GetPath() As String
End Interface
Public Class LogFilePathFinder
Implements ILogFilePathFinder
Public Sub New(isOemVersion As Boolean)
_isOemVersion = isOemVersion
End Sub
Private _isOemVersion As Boolean
Function GetPath() As String Implements ILogFilePathFinder.GetPath
If _isOemVersion Then
Return "C:\TestOem.log"
Else
Return "C:\Test.log"
End If
End Function
End Class
Public Interface ILogger
Sub WriteLog(ByVal text As String)
End Interface
Public Class FileLogger
Implements ILogger
Public Sub New(pathFinder As ILogFilePathFinder)
_pathFinder = pathFinder
End Sub
_pathFinder As ILogFilePathFinder
Public Sub WriteLog(text As String) Implements ILogger.WriteLog
Dim path As String = _pathFinder.GetPath()
' Write text to file ...
End Sub
End Class
As you can see, it requires a little bit of extra work, but when you design your code like this, you'll never regret it. You'll notice that the logger class requests a path finder as a dependency. The path finder, in turn, requests an OEM setting as a dependency. So, to use it, you would need to do something like this:
Dim pathFinder As ILogFilePathFinder = New FileLogPathFinder(_OemSettings.IsOemVersion) ' Note, don't use a global to store the settings, always ask for them to be injected
Dim logger As ILogger = New FileLogger(pathFinder)
logger.WriteLog("test")
Now, you can easily reuse all of this code in any situation. For instance, if you have different projects that need to use a different log file path, they can still use the common FileLogger class, they just need to each implement their own version of ILogFilePathFinder and then inject that custom path finder into the common FileLogger. Hopefully you see how doing it this way can be very useful and flexible.

Visual Studio - manage multiple files that are part of one Class - classes, modules

My VB project is large enough that it requires several files. It was originally developed as a Console App and I created each file as a MODULE. All modules could use subroutines, data structures and constants from other MODULES and everything worked fine. I needed to add basic windowing to the app and this required that the app be converted from a Console App to a Windows Forms App. The main window is Form1 which is not a MODULE but a CLASS. The problem is that some MODULE based functions cannot access subroutines, data and constants that are defined within the CLASS Form1 unless they are incorporated into the CLASS file and this makes the CLASS file very large. If I add a new Class file to the project, it also cannot interoperate with Class Form1 in the same way that multi-MODULE code interoperates.
How does one spread CLASS code across several files and still allow it to interoperate as if it were in a single file? Alternatively, how does one create several CLASS files that operate the way multiple MODULE files operate.
I am sure that there are all kinds of best practices that I am violating but the goal to to get some prototype software working and interfaced to some lab equipment.
Thank you in advance
Use a partial class (Partial keyword on the class declaration). Each partial "bit" of the class will be merged at compile time. All partial bits must be in the same project.
Modules are default shared and do not require initialization with the New keyword. When you made your console app a windows app, it became a class...You could change it to the same behavior as a module simply by making it a Public shared Class and making all properties and methods inside shared as well.
so while you can access your methods and properties in your modules without initialization, you would need to use the NEW method to initialize your Class methods.
To access the Class from the module you would simply have to use:
SomeModulemethod
dim x as new CLASS
CLASS.SOMEMETHOD
someModuleMethod End
You could also use Partial Classing to split up your Classes, but it is much better to decide if you really need a separate class for what you want to do.