In my VB.NET application, I would like to move some code (a class) into a separate file. The separate file will use functions located in the main project.
If I create a Class Library, functions called from the DLL are not defined in the DLL and Visual Studio won't compile it.
In what ways could I move code into file and load/execute it at runtime and get the result the my main code? I don't know if I'm clear...
This can be done indirectly using interfaces. Create a public interface in the library that has the calls you need to make against that main project's class. Have the main project's class implement this interface. When the main projects starts have it pass in instance of this class in to the library project via the interface. The library should store this reference. It can now makes calls against the main projects class using this reference through the interface.
The Library Project:
Public Interface ITimeProvider
ReadOnly Property Time As Date
End Interface
Public Class LibraryClass
Private Shared _timeProvider As ITimeProvider
Public Shared Sub Init(timeProvider As ITimeProvider)
_timeProvider = timeProvider
End Sub
Public Function GetTimeString() As String
Return "The current time is " & _timeProvider.Time.ToString
End Function
End Class
The Main Project:
Public Class SimpleTimeProvider
Implements ClassLibrary1.ITimeProvider
Public ReadOnly Property Time As Date Implements ClassLibrary1.ITimeProvider.Time
Get
Return Date.Now
End Get
End Property
End Class
Public Class MainClassTest
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
ClassLibrary1.LibraryClass.Init(New SimpleTimeProvider)
Dim test As New ClassLibrary1.LibraryClass
Console.WriteLine(test.GetTimeString)
End Sub
End Class
This example has the library project using a class that is defined in the Main project.
Simple answer is - you can't.
You can't have assemblyA referencing assemblyB and assemblyB referencing assemblyA
The solution is probably to move any code that is used by both your application and assembly into the assembly. Then both can access this code
Related
I am using a Public Enum in a Class Library that is used within different classes within the library. I don't want it exposed to any applications that use the Class Library. I tried changing it to Private, but it says it has to reside within a Class to do that (which I can't do because it is used by many classes). How do I 'hide' it?
EDIT: Sorry about no code. Here's some code from the Class Library (I know it's vb, but I figure c# knowledge will be applicable?)
Public Enum HttpMethod
[Get]
Post
Put
End Enum
Public Class WebClientProcessor
Public Function HttpAction(netquery As String, method As HttpMethod, Optional json As String = Nothing) As WebClientResponse
' Stuff here
End Function
End Class
Public Class Main
Public Sub DoStuff
Dim wcp As New WebClientProcessor
wcr = wcp.HttpAction(StringOp.UrlCombine(_baseSiteURL, _licenseEndpointsMap(RequestType), LicenseKey), HttpMethod.Get)
End Sub
End Class
Use the internal modifier.
Internal types or members are accessible only within files in the same assembly.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/internal
I eventually solved it by removing the "Public" just to read:
Enum HttpMethod
[Get]
Post
Put
End Enum
I need help converting some of this code. Mainly:
private static void SetProvider(ServiceCollection collection)
=> _service = collection.BuildServiceProvider();
and the line below it. This is being used for a discord bot using Discord.Net with the music library Victoria. Can someone also tell me what this actually is? Just a side question. this uses static classes and there's not anything called static on VB.Net so what would be the best call here? I've seen some other posts from here debating whether to use NonInheritable Class or a Module. What are the differences and when it is better to use either one?
It depends on what you want exactly. VB.NET does not provide static classes. Instead, it offers modules, but those are not completely equal to static classes.
The module version would be:
Public Module ServiceManager
Private _service As IServiceProvider
Public Sub SetProvider(collection As ServiceCollection)
_service = collection.BuildServiceProvider()
End Sub
Public Function GetService(Of T As New)() As T
Return _service.GetRequiredService(Of T)()
End Function
End Module
The class version would be:
Public NotInheritable Class ServiceManager
Private Sub New()
End Sub
Private Shared _service As IServiceProvider
Public Shared Sub SetProvider(collection As ServiceCollection)
_service = collection.BuildServiceProvider()
End Sub
Public Shared Function GetService(Of T As New)() As T
Return _service.GetRequiredService(Of T)()
End Function
End Class
When using the class implementation, you have to be careful to mark all members as Shared. Additionally, you can consider the following:
Declare the class as NotInheritable, since neither VB.NET modules nor C# static classes can be inherited from. (The corresponding C# keyword is sealed, by the way, but it will never be used in this context, since C# does support static classes.)
Create one private (default) constructor for the class. That will make sure that you cannot instantiate the class. VB.NET modules nor C# static classes cannot be instantiated either.
Using VB.NET modules is somewhat more straightforward, but keep in mind that VB.NET modules have a little quirk. When accessing a member of a module, you are typically not required to prefix it with the module name. Suppose you have some kind of service class called MyService and you have implemented your ServiceManager as a module. Then you do not need to call it like:
Dim svc As MyService = ServiceManager.GetService(Of MyService)()
Instead, you could just call it like:
Dim svc As MyService = GetService(Of MyService)()`.
When using the former method, Visual Studio actually suggests to simplify the name and change it to the latter method. But when you afterwards add another imported namespace that also happens to contain a module that has a GetService(Of T)() method, you will get an error indicating that GetService is ambiguous, in which case you would be forced to prefix it with the module name (like in the former method).
I personally find this checking behavior in Visual Studio regarding VB.NET module member usage to be rather annoying and confusing. I prefer prefixing calls with the module name (for the sake of writing self-documenting code and avoiding ambiguity as mentioned), but I do not want to disable the "simplify name" hint/suggestion in Visual Studio. So I personally prefer a class implementation instead of a module implementation when implementing something in VB.NET that mimics a C# static class.
Or even better: I would avoid a static class design and switch to a "regular" class design when possible. Using class instances has several advantages, like using composition (which is also an important technique used in many popular behavioral design patterns), simplified mocking/unittesting, and less side effects in general.
The equivalent VB.NET is:
Private Shared Sub SetProvider(collection As ServiceCollection)
_service = collection.BuildServiceProvider()
End Sub
C# expression bodies are just a single expression body method, MS Docs e.g. the following are equivalent:
void Greet()
{
Console.WriteLine("Hello World");
}
// Same as above
void Greet() => Console.WriteLine("Hello World");
I can read a lot over the Internet that VB.Net Modules are the same thing as c#.Net Static Classes. I can also read that something close to a Static Class is a class which would look like this:
'NotInheritable so that no other class can be derived from it
Public NotInheritable Class MyAlmostStaticClass
'Private Creator so that it cannot be instantiated
Private Sub New()
End Sub
'Shared Members
Public Shared Function MyStaticFunction() as String
Return "Something"
End Function
End Class
I find this code heavy to draft, and to read. I would be much more confortable just using a Module like this:
Public Module MyEquivalentStaticClass
Public Function MyStaticFunction() as String
Return "Something"
End Function
End Module
However, with a Module you loose one level of Namespace hierarchy, and the following 3 statements are equal:
'Call through the Class Name is compulsory
Dim MyVar as String = Global.MyProject.MyAlmostStaticClass.MyStaticFunction()
'Call through the Module Name is OPTIONAL
Dim MyVar as String = Global.MyProject.MyEquivalentStaticClass.MyStaticFunction()
Dim MyVar as String = Global.MyProject.MyStaticFunction()
I find this very inconvenient and this either pollutes the Intelisense, or forces me to create additionnal levels of Namespace, which then means more Module declaration, i.e., more Intelisense pollution.
Is there a workaround or is this the price to pay if you want to avoid the heavy SharedMembers-NotInheritable-PrivateNew Class declaration?
Additionnal references include the very good post by Cody Gray: https://stackoverflow.com/a/39256196/10794555
No, there is no exact equivalent to a C# static class in VB.NET. It would be nice if VB had the ability to add the Shared modifier to a class declaration, like this:
Public Shared Class Test ' This won't work, so don't try it
' Compiler only allows shared members in here
End Class
But, unfortunately, it does not. If you do that, the compiler gives you the following error:
Classes cannot be declared 'Shared'
That leaves us with the two options you listed:
Either you make a non-instantiable class containing only Shared members (without the safety of that rule being enforced by the compiler), or
Use a Module, which makes everything Shared, even though you don't explicitly say so via the Shared modifier
As you said, many people don't like the loss of the class name being required, as a sort-of extra namespace layer, so they prefer the Class with only Shared members over the Module. But, that's a matter of preference.
It's worth noting that, while you don't have to specify the module name everywhere you call its members, you can always do so if you wish:
MyModule.MyMethod()
While a "SharedMembers-NotInheritable-PrivateNew Class", as you so eloquently called it, is the closest approximation to a static class, it's only functionally equivalent. If you use reflection, you'll see that the attributes of the type are not the same. For instance, in VB:
Module MyModule
Public Sub Main()
Dim t As Type = GetType(MyClass)
End Sub
End Module
Public NotInheritable Class MyClass
Private Sub New()
End Sub
Public Shared Sub MyMethod()
End Sub
End Class
If you take a look at t.Attributes, you'll see that it equals Public Or Sealed. So the MyClass type is both sealed (NotInheritable) and public. However, if you do this in C#:
class Program
{
static void Main(string[] args)
{
Type t = typeof(Test);
}
}
public static class MyClass
{
public static void MyMethod()
{ }
}
And you inspect the t.Attributes again, this time, the value is Public | Abstract | Sealed | BeforeFieldInit. That's not the same. Since you can't declare a class in VB as both NotInheritable and MustInherit at the same time, you have no chance of exactly duplicating that thing. So, while they more-or-less are equivalent, the attributes of the types are different. Now, just for fun, let's try this:
Module MyModule
Public Sub Main()
Dim t As Type = GetType(MyModule)
End Sub
End Module
Now, the t.Attributes for the module are Sealed. That's it. Just Sealed. So that's not the same either. The only way to get a true static class in VB (meaning, the type has the same attributes when inspected via reflection) is to write it in a C# class library, and then reference the library in VB.
I would be much more confortable just using a Module
So use a Module.
Module SomeModuleNameHere
Public Function MyStaticFunction() As String
Return "Something"
End Function
End Module
You don't need Global.MyProject or the Module name at all, just call your function directly, from anywhere:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim x As String = MyStaticFunction()
Debug.Print(x)
End Sub
But if you want to, you can use the Module name, without the Global part:
Dim x As String = SomeModuleNameHere.MyStaticFunctions
The only time you must use the Module name, however, is if you have two functions with the exact same name in different modules. Then you'd have to differentiate them by using their fully qualified names.
From all the discussions held so far, and thanks to the input by Steven Doggart and comments by TnTinMn, I have come to conclude with the following broad feedbacks and guidelines.
Nota: This post refers to 'Static' Classes, whilst the Static keyword is used for C#.Net, not VB.Net. The VB equivalent is Shared, but Shared Classes are not permited with VB (only the Members). The guidelines described below are tentatives to achieve in VB something close to a C# Static Class.
Since such VB Classes cannot be Shared, they are described as 'Static'.
Nota bis: In all the examples, I purposely added a layer of Namespace (consistently called "MySpace") so that there is no confusing as to in which Namespace layer the examples sit: they are all in the MySpace layer. The MySpace layer is not compulsory and can be stripped out depending on your needs.
In general
Use a Module but do not rely on the Module name as a Namespace layer. Rather, fully integrate the path in a Namespace declaration, such as:
Namespace MySpace.MyStaticClass
Module _Module
Function MyStaticFunction()
Return "Something"
End Function
End Module
End Namespace
Then the Static 'Members' should be accessed via Global.MyProject.MySpace.MyStaticClass.MyStaticFunction()
Nota: Part of the Namespace path can be stripped depending on where
you are located. Usually, MySpace.MyStaticClass.MyStaticFunction()
will be sufficient.
Nota bis: Using _Module as the Module name will
reduce the appereance of the Module in the Intelisense dropdown, and
yet make it crystal clear this is a Module.
When wishing to encaspulate Static Classes
Under such context the general above-mentionned style would produce:
Namespace MySpace.MyStaticClass
Module _Module
Function MyStaticFunction()
Return "Something"
End Function
End Module
End Namespace
Namespace MySpace.MyStaticClass.MyStaticSubClass1
Module _Module
Function MyStaticFunction()
Return "Something"
End Function
End Module
End Namespace
Namespace MySpace.MyStaticClass.MyStaticSubClass2
Module _Module
Function MyStaticFunction()
Return "Something"
End Function
End Module
End Namespace
This can quickly be heavy in the sense that it requires a separate Namespace declaration for each 'encapsulated' 'Static Class'. Disadvantages include:
Heavy review because understanding the Namespace architecture/arborescence will be less intuitive: in the above example that would mean checking all the declaration which include 'MyStaticClass'.
Heavy drafting because of the additionnal Namespace declarations.
Heavy maintenance because changing a parent Namespace will require a change in several Namespace declarations: in the above example that would mean changing 'MyStaticClass' 3 times. (Right-Click/Rename is your best friend here)
An alternative is to use encapsulated Classes with Shared members:
Namespace MySpace
Public Class MyStaticClass
Public Function MyStaticFunction()
Return "Something"
End Function
Public Class MyStaticSubClass1
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
Public Class MyStaticSubClass2
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
End Class
End Namespace
Nota: As Steven Doggart pointed out in a separate post, people usually import Namespaces, but do not import Classes, so encapsulating Classes will usually "force" the reliance on the full path across encapsulated Classes : MyStaticClass.MyStaticSubClass1.
You cannot encapsulate a Module within another Module, but you could always use a mixture of a Module in which you encapsulate one or several Classes and Sub-Classes. The example below achieves something similar to the above example:
Namespace MyStaticClass
Public Module _Module
Public Function MyStaticFunction()
Return "Something"
End Function
Public Class MyStaticSubClass1
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
Public Class MyStaticSubClass2
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
End Module
End Namespace
When publishing a Class Library (DLL)
If your final product is a DLL you intend to share with a broader audience, it is recommended to put safety nets around your 'Static' Classes. Although this will not affect how the compiler will see your code, it will prevent someone else from making mistakes, or at least quickly trigger errors and assist debugging swiftly:
Make the Class NotInheritable, so that no one tries to derive a Class from a Static Class: it is typically useless to derive such Classes.
Make the New Creator statement Private, so that no one tries to instantiate the Class: the Static Class should not include any non-Static (Shared) members; if so, that is a typo and trying to instantiate the non-Shared Member will likely bring problems.
The example below achieves something similar to the above examples:
Namespace MySpace
Public NotInheritable Class MyStaticClass
Private Sub New()
End Sub
Public Function MyStaticFunction()
Return "Something"
End Function
Public NotInheritable Class MyStaticSubClass1
Private Sub New()
End Sub
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
Public NotInheritable Class MyStaticSubClass2
Private Sub New()
End Sub
Public Shared Function MyStaticFunction()
Return "Something"
End Function
End Class
End Class
End Namespace
When dealing with an Extension
A <System.Runtime.CompilerServices.Extension()> can only be declared within a Module block. However the Module Name has no impact on the Extension so this topic is not really relevant here.
See link provided by Peter Macej: https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/extension-methods
I have an application.
Module1 - Main application
DataAccessMananger - Class in main application to handle data
Configuration - Class in a different project (common dll) that handles configuration settings.
The problem / Question. How can the Configuration class handle a data changed event in the DataAccessMananger without it knowing what a DataAccessManager is since they are in different classes?
The only way I can think of making it work is to have Module 1 handle the event from the DataAccessMananger and have it call a method in the Configuration class, however I dont like this, I would rather Configuration be able to handle its own data updates...
Clear as mud? Any ideas? VB.NET 4.5, and I know a bit about delegates, but not sure how I could use them here, they must be the answer some how...
Ideally, I would like to be able to pass an "Event" to the config class from the DAM class using the module...
The best way I can think of would be to add an interface in the configuration class (common.dll) that would be implemented by the DataAccessMananger. I assume the mainmodule is aware of both the DataAccessMananger and the Configuration, right ? If so, the following might be a solution.
Add an interface to common.dll for the Configuration class to use (not implement) that contains the event to be managed. For instance:
Public Interface IConfiguration
Event ConfigChanged(sender As Object, e As configPropertyChanged)
End Interface
In my case, I also create a class inheriting Event args.
Public class configPropertyChanged
Inherits EventArgs
Public Property PropertyName() As string
Public Property NewValue() As String
Public Property OldValue() As String
Public sub New(Newvalue as string,OldValue as string,<CallerMemberName()> optional PropertyName as string = "")
Me.NewValue = Newvalue
Me.OldValue =OldValue
Me.PropertyName = PropertyName
End sub
End Class
The configuration class is then modified to be able to monitor any class (which means that in the main module, the configuration must be made aware of the DataAccessManager class (Notice Idisposable is implemented to cleanup).
Public Class Configuration
Implements IDisposable
Private _ConfigList As New List(Of IConfiguration)
Public Sub RegisterConfig(Config As IConfiguration)
_ConfigList.Add(Config)
AddHandler Config.ConfigChanged, AddressOf ConfigChanged
End Sub
Public Sub ConfigChanged(sender As Object, e As configPropertyChanged)
Console.WriteLine("Config has changed.")
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
Public Sub Dispose() Implements IDisposable.Dispose
For Each config As IConfiguration In _ConfigList
RemoveHandler config.ConfigChanged, AddressOf ConfigChanged
Next
_ConfigList.clear()
End Sub
#End Region
End Class
DataAccessManager does implement the Iconfiguration interface (available from common.dll)
Public Class DataAccessMananger
Implements IConfiguration
Public Event ConfigChanged(sender As Object, e As configPropertyChanged) Implements IConfiguration.ConfigChanged
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(value As String)
If String.Compare(_Name, value, True) <> 0 Then
RaiseEvent ConfigChanged(Me, New configPropertyChanged(Value,_Name))
_Name = value
End If
End Set
End Property
End Class
Finally, the main module, which is the only one to be aware of the existence of both Configuration and DataAccessManager, register the DataAccessManager into the configuration.
Public Sub Main()
Dim MyManager As New DataAccessMananger
Dim MyConfig As New Configuration
MyConfig.RegisterConfig(MyManager)
MyManager.Name = "New name"
End Sub
In this scenario.
The main module load the configuration and the data access manager at some point and then, register the data access manager into the configuration object. It can also register any other class implementing the Iconfiguration process.
At some point, something triggers a raise event into the data access manager (In my example, changing the property name do exactly that). The data access manager raise the event, which the configuration object handles it since we registered the data class into the configuration object.
If you wanted, you could have skipped the interface entirely and just had the DataAccessManager raise an event to the main module, then in the main module event handler, call a public method from the configuration class.
I need to scan my assembly and register all classes that have a default interface with Castle.
For example: MySpecialClass should be registered if IMySpecialClass exists.
vb.net registry:
Public Class UiRegistry
Implements IWindsorInstaller
Public Sub Install(ByVal container As IWindsorContainer, ByVal store As IConfigurationStore) Implements IWindsorInstaller.Install
container.Register(Classes.FromThisAssembly().)
End Sub
End Class
This is where i got but i can't find any implementation that provide what i require.
It was quiet simple:
container.Register(Classes.FromThisAssembly().Pick().WithServiceDefaultInterfaces())
I just needed to use the .Pick() to select the Classes and then i could select the option to configure there interfaces.