When are a module's variables in VB.NET instantiated? - vb.net

I was wondering where in the lifetime of the program a variable that is in a module would be initialized as in this example:
Module Helper
Friend m_Settings As New UserSettings()
Sub Foo()
'...
End Sub
Sub Bar()
'...
End Sub
End Module
Public Class UserSettings
Public Property UserName As String
Public Property PrefServer As Integer
Public Sub New()
'...
End Sub
Public Sub LoadSettings()
'...
End Sub
End Class
When would m_Settings be initialized? I can set a break point at the constructor for UserSettings and look at the call stack, but I see "External Code" in there but that doesn't tell me a lot.

The CLR has no direct support for VB.NET modules, it requires all methods and variables to be part of a type. So the VB.NET compiler actually generates a class under the hood. All of the functions you wrote in the module become static methods of that class. All of the variables you declared in the module become static fields of the class.
Any variables that are initialized in your module causes a static constructor to be generated. And the initialization code is moved into this constructor.
Now CLR rules apply: a soon as the jitter touches any of the members of this class, the CLR runs the static constructor. Which then initializes all of the module variables. Which is also why you see [external code] on the call stack, the call originated inside the CLR.
It is rare to have problems with this, the static constructor guarantee in the CLR is a very strong one. About the only tricky mishap is a variable initializer that causes an exception to be thrown. That's when the guts start showing. The stack trace is pretty mystifying since it shows code that doesn't exist in your source code. The actual exception thrown is a TypeInitializationException, very mystifying since you didn't write any type, you need to look at its InnerException to find the real reason.

Related

Translating C# functions into vb.net

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");

Named Constructor Idiom in VB.NET?

Is using the Named Constructor Idiom possible in VB.NET? I've found many examples in C#/C++ but can't quite wrap my head around how to use it in vb.net. Seems like a better method of keeping my code readable when involving a lot of constructors with similar argument types.
I've never heard this term before, but after a quick search it sounds vaguely like the Static Factory Pattern. The idea is you make the constructor private and use a shared (static in c#) public function to create the new object.
Public Class Foo
Private Sub New()
End Sub
Public Shared Function CreateNew(param as Object) as Foo
Dim obj as New Foo()
obj.Prop = param
return obj
End Function
End Class
You sure can make Named Constructors in VB. The pattern uses a static (Shared in VB) factory method on the class itself, so that the method can be named. (Other Factory patterns involve using a separate Factory class to provide the static method.)
System.Drawing.Color is a simple example. The pattern is implemented underneath as a static (Shared) property. Since no arguments are necessary, the Get method of a Property works just fine:
Public Shared ReadOnly Property Chartreuse As Color
Usage:
Dim favoriteColor as Color = Color.Chartreuse
Or you can make static factory methods to do the same thing.
Public Class TheClass
Public Sub New()
End Sub
Public Sub New(input As String)
'do something with input
End Sub
Public Shared Function MyNamedConstructor() As TheClass
Return New TheClass
End Function
Public Shared Function AnotherNamedConstructor() As TheClass
Return New TheClass("Another Name")
End Function
End Class
As for whether this pattern is "better" than overloading constructors, that's really an opinion. Personally, I would just overload the constructors. As you can see in the example above, the constructors need to be there anyway.
I suggest using the Named Constructor pattern when you have only a few possible ways to construct your class/struct, but consumers of your class/struct will be using those few constructors often, and with different input values to those constructors (as in the System.Drawing.Color example).
The Name in 'Named Constructor' doesn't represent a name for the constructor itself, but for the object resulting from the constructor. If your named constructor can be used to create two objects that don't feel right to give the same name to, then don't give the constructor that name.

String.Substring(start, end) sometimes throwing an exception

My program uses a BackgroundWorker to call a PerformAction() method when a different method, Method1 returns true. I also am using the Strategy Pattern to set the correct PerformAction() that should be performed every time the event is raised.
For the Strategy Pattern I created an Abstract Class, and then a class inside the abstract class that inherits it.
Public MustInherit Class Abstract
Public MustOverride Sub PerformAction(ByVal str as String)
Public Class Extends
Inherits Abstract
Public Overrides Sub PerformAction(ByVal str as String)
str = str.Substring(str.IndexOf(":"), str.IndexOf(">"))
MsgBox(str)
End Sub
End Class
I create another class that contains a field of Abstract, and that is used to call PerformAction.
The PerformAction method gets called from the BackgroundWorker.ReportProgress event, which is called when BackgroundWorker.DoWork detects that Method1 is returning true. And with the code above, it causes a System.Reflection.TargetInvocationException with addition information Exception has been thrown by the target of an invocation.
The debugger tells me:
this Cannot obtain value of local or argument '<this>' as it is not available at this instruction pointer, possibly because it has been optimized away. System.Delegate
args Cannot obtain value of local or argument 'args' as it is not available at this instruction pointer, possibly because it has been optimized away. object[]
Strangely enough, when I perform (what seems to me) an identical operation with two substrings:
s = s.Substring(s.IndexOf(":"))
s = s.Substring(0, s.IndexOf(">"))
it functions perfectly.
What is the difference between these two methods? Is my inheritance set up incorrectly and that is what is causing these errors? What's going on here?
Let me know if I need to add more code to explain the situation. Thanks.
To get the effect of
s = s.Substring(s.IndexOf(":"))
s = s.Substring(0, s.IndexOf(">"))
in a single statement, you need to calculate the length of the desired substring
s = s.SubString(s.IndexOf(":"), s.IndexOf(">") - s.IndexOf(":"))
Note that if it is possible that the string does not contain a ":" followed later by a ">", you will need to first verify that IndexOf(":") is >= 0 and that s.IndexOf(">") returns a value greater than IndexOf(":").

Suppress obsolete warning on factory method in vb.net

Is it possible to prevent compiler warning caused by a static factory method returning an instance of an obsolete class?
For example if an instance of an obsolete class (Foo) is created through a static method (Create) a compiler warning is caused by the factory method.
<Obsolete()> _
Public Class Foo
Public Shared Function Create() As Foo
' Instantiate and return
End Function
End Class
In C# the warning could be suppressed using "#pragma warning..." but I don't think that this exists within VB.Net. Migrating to C# is not an option due to business requirements.
I think you have to open the .vbproj-file with notepad, search the NoWarn-Tag and add the error-id there(618 should be obsolete-warning):
<NoWarn>618,42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>

Run-time error 459 when using WithEvents with a class that implements another

I am developing a VBA project in Word and have encountered a problem with handling events when using a class that implements another.
I define an empty class, IMyInterface:
Public Sub Xyz()
End Sub
Public Event SomeEvent()
And a class, MyClass that implements the above:
Implements IMyInterface
Public Event SomeEvent()
Public Sub Xyz()
' ... code ...
RaiseEvent SomeEvent
End Sub
Private Sub IMyInterface_Xyz()
Xyz
End Sub
If I create a third class, OtherClass, that declares a member variable with the type of the interface class:
Private WithEvents mMy As IMyInterface
and try to initialize this variable with an instance of the implementing class:
Set mMy = New MyClass
I get a run-time error '459': This component doesn't support this set of events.
The MSDN page for this error message states:
"You tried to use a WithEvents
variable with a component that can't
work as an event source for the
specified set of events. For example,
you may be sinking events of an
object, then create another object
that Implements the first object.
Although you might think you could
sink the events from the implemented
object, that isn't automatically the
case. Implements only implements an
interface for methods and properties."
The above pretty much sums up what I'm trying to do. The wording, "that isn't automatically the case", rather than "this is flat-out impossible", seems to suggest that there is some bit of manual work I need to do to get it to work, but it doesn't tell me what! Does anybody know if this is possible in VBA?
Apparently Events are not allowed to be passed through an interface class into the concrete class like you want to using "Implements". In this article it states: "Event declarations of the abstract interface are not included in the interface that is inherited by concrete classes. I haven't found anywhere that this has been acknowledged as a bug; however, it does seem to be one."
Here is the link to the source: http://www.devx.com/getHelpOn/10MinuteSolution/20416
:-(