Suppress obsolete warning on factory method in vb.net - 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>

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

Proper Interface (Implements) syntax for class method with signature (Of T As Class)() As T

I have a hard time to either figure out the correct interface or actual implementation signature/syntax for a method. The method itself works as expected, the compiler at least doesn't complain about the interface's syntax, but when actually adding the necessary Implements statement to the method, it fails.
Here's what I have:
Public Interface IMyInterface
Function GetIt(Of T As Class)() As T
End Interface
Public Class Foo
Implements IMyInterFace
Public Function GetIt(Of T As Class)() As T
End Class
If I now try to add the necessary Implements statement, even using autocompletion from the IntelliSense popup, VS complains about the syntax. Without the Implements statement, VS complains:
BC30149 Class 'Foo' must implement 'Function GetIt(Of T As
Class)() As T' for interface 'IMyInterface'.
First, doing so by using autocompletion ends up with the following incomplete line:
Public Function GetIt(Of T As Class)() As T Implements IMyInterface.GetIt(Of
VS obviously complains about a)
'Type expected'
and b)
')' expected
Second, upon completing that line with
Public Function GetIt(Of T As Class)() As T Implements IMyInterface.GetIt(T As class) As T
VS still reports
')' expected
and points to the 'A' in the parameter definition 'As Class'.
So what's the right syntax for this kind of method signature?
You're both correct, the solution is
Public Function GetIt(Of T As Class)() As T Implements IMyInterface.GetIt
I also had the idea of letting VS do the refactoring (Edit -> Refactor -> Extract Interface) and the above is what VS did that way. I still find it strange that VS (2017)'s autocompletion yields a different result.
MyClass is a keyword, so you can't name the class that.
You can close keywords in square brackets in VB.NET to avoid that.
Public Interface IMyInterface
Function GetIt(Of T As Class)() As T
End Interface
Public Class [MyClass]
Implements IMyInterface
Public Function GetIt(Of T As Class)() As T Implements IMyInterface.GetIt
Throw New NotImplementedException()
End Function
End Class
But since this is just a proof of concept, your actual implementation probably won't suffer from this issue.
By the way, I'm voting to close your question because it's more of a question about using MyClass as a class name. If you hadn't done that your auto-complete surely would have generated the proper method signature. Instead your IDE was getting confused by the misplaced keyword. I hope this helped you solve your problem

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

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.

MyBase can not to be used in a Extension Method?

I created a module to add some Extension Methods to a Class.
This Class inherits from another parent Class.
In the code of my Extension Methods, I would like to refer to the base Class using MyBase.
This doesn't seems to be allowed (Error message : "'MyBase' is not valid within a Module.")
<Extension()>
Public Function Get_OutOfSpace(val as ClassA) As Boolean
Return MyBase.IsOutOfSpace()
End Function
How can I invoke a method of my base class within an Extension Method?
That's why they force you to write extension methods in a module, so you can't make the mistake of using MyBase. But there's at least one other thing wrong with your code, you didn't extend anything. The first argument of an extension method must be a reference to the object, of the type you want to extend:
<Extension()>
Public Function Get_OutOfSpace(ByVal obj As Foo) As Boolean
''...
End Function
So a likely implementation is Return obj.IsOutOfSpace. Which in turn makes it very likely that you don't actually have any use at all for this extension method since the class you want to extend already has an IsOutOfSpace property.
Only use extension methods to add methods to classes. And only do so if you can't change the class.

FxCop giving a warning on private constructor CA1823 and CA1053

I have a class that looks like the following:
Public Class Utilities
Public Shared Function blah(userCode As String) As String
'doing some stuff
End Function
End Class
I'm running FxCop 10 on it and it says:
"Because type 'Utilities' contains only 'static' (
'Shared' in Visual Basic) members, add a default private
constructor to prevent the compiler from adding a default
public constructor."
Ok, you're right Mr. FxCop, I'll add a private constructor:
Private Utilities()
Now I'm having:
"It appears that field 'Utilities.Utilities' is
never used or is only ever assigned to. Use this field
or remove it."
Any ideas of what should I do to get rid of both warnings?
In C# this problem would be handled by marking the class as static, e.g.
public static class Utilities
{
...
}
A static class can only contain static (in VB shared) members.
I believe the equivalent in VB.NET is to use a module.
See Marking A Class Static in VB.NET.