Can I conditionally compile "Select Case"? - vb.net

The MSDN article on #If Then #Else (https://msdn.microsoft.com/en-us/library/tx6yas69.aspx) gives me the basics on conditionally compiling conditional statements.
I happen to have longer lists of declarations that must be initialized differently, based upon multiple platforms. Am I required to use #ElseIf at compile time, or is there a #Select Case option too?

No there are no #Select Case directives in VB .Net (as pointed out by Icepickle)
According to Conditional Compilation, you can define compilation constants #Const and test them to include or exclude blocks of code.
If you have a lot of different architectures/platforms, maybe it is better to write a different file for each platform, and protect the file with the constant check
First you declare an interface so the rest of your code will always be able to find what it needs :
Public Interface IPlatformDependant
Property Test1 As Integer
'Define here all the parameters used by your application
End Interface
File platform1.vb :
#If Platform = 1
'The code for the first platform
Public Class PlatformDependant
Implements IPlatformDependant
Public Property Test1 As Integer Implements IPlatformDependant.Test1
End Class
#End If
File platform2.vb :
#If Platform = 2
'The code for the second platform
Public Class PlatformDependant
Implements IPlatformDependant
Public Property Test1 As Integer Implements IPlatformDependant.Test1
End Class
#End If
In your project designer, you define platform to which you want, and only one class PlatformDependant will be used at a time. The classname can even stay the same...
The Interface here is optional, but it makes you sure that all your classes implements the required method.

Related

How to extend derived classes by defining class(es) that exposes the instance as a property

I have a class that I would like to extend by defining a new class that contains the first class as a public property, as well as additional added properties. However, the class that I'm extending has multiple derived types, which should be treated the same in the extension class.
Below is an example of what I am trying to do:
Public Class ClassA
End Class
Public Class ClassB
Inherits ClassA
End Class
Public Class ClassC
Inherits ClassA
End Class
Public Class BaseExtended
Public Property Foo As ClassA
Public Property ExtendedMetaData1 As Double
Public Property ExtendedMetaData12 As Integer
End Class
Public Class DerivedExtendedB
Inherits BaseExtended
Public Property Foo As ClassB
End Class
Public Class DerivedExtendedC
Inherits BaseExtended
Public Property Foo As ClassC
End Class
The code that uses an instance of any of the 'extended' classes would then need use that instance appropriately depending on it's type. There would be many cases where the property 'Foo' needs to be accessed and modified outside of the class that it belongs to.
If I were to implement something like what I have shown above, that would require that I first cast it to the required type before accessing or modifying it. Ideally I would like to do that inside the 'DerivedExtended' class; The alternative, I think, would be to duplicate code to cast that property would [hundreds of times] in the client code.
Private Sub ClientUsesObject(bar As BaseExtended)
' Perform a task that is agnostic Foo type
' Would not require that Foo be cast to any specific type
If bar.GetType() Is GetType(DerivedExtendedB) Then
Dim barCast As DerivedExtendedB = DirectCast(bar, DerivedExtendedB)
' Perform task that requires Foo to be of type ClassB
ElseIf bar.GetType() Is GetType(DerivedExtendedC) Then
Dim barCast As DerivedExtendedC = DirectCast(bar, DerivedExtendedC)
' Perform task that requires Foo to be of type ClassC
End If
End Sub
What I'm looking for is advice outlining or describing a design pattern that can handle this situation. I've searched for quite a while, and have not been able to find any examples that solve this problem.
I realize that this may be somewhat of an "XY" problem. I'm working with existing code that simply assumes all instances are of the same derived type (when in fact some instances are of the other derived type). As such, the existing code does not work. To me what I've tried to outline above seems like the most straightforward path, but I'm open to alternative if this is just the wrong approach.
This pattern of type covariance in derived classes is the canonical reason for what is called in C++ the "Curiously Recurring Template Pattern" and has been called in .NET the "Curiously Recurring Generic Pattern." I believe it's also sometimes referred to as "F-Bounded Polymorphism" (not a computer scientist, so I might have the reference wrong).
You can write a base class like this:
Public Class Base(Of TDerived As Base)
Public Overridable Property foo As TDerived
End Class
And then use it like this:
Public Class MyDerived
Inherits Base(Of MyDerived)
End Class
Then, the derived class has a property foo whose type is MyDerived. No casting required by clients.
However, this has some limitations. It works best when you don't need to switch back and forth between derived and base. There is no one Base, so you can't declare instances of it. If you want to be able to declare something as Base, then you end up needing to fall back on a non-generic base class. This will still work well for certain usage patterns where you don't need to convert from base to derived, but otherwise you run right back into the casting problems you are trying to avoid.
Eric Lippert has written a bit about this pattern. He's always interesting to read, so I'd recommend looking up his commentary.
Another alternative to consider, if the generic approach doesn't work for you, is code generation. You can use T4 templates to process a compact description of what your code should be, and generate the code files from them. A long list of casts is less tedious if you only write the machinery to generate it, you don't write them all out explicitly.

Can't access methods in DLL

Using asp.net/vb.net. Created a solution with 2 projects, "MainProject" and "MyCommonStuff". The 2nd project ("MyCommonStuff") is really a common utilities class, the resulting dll I hope to use for other projects as well.
MyCommonStuff is defined very simply....
Public Class MyCommonStuff Stuff
Public Shared Function GetInfo() as string
:
:
End Function
Public Shared Sub Test
:
:
End Sub
:
End Class
In MainProject I set a reference to this MyCommonStuff project.
I want to access some of the MyCommonStuff methods in my code. But for some reason the methods are not being recognized.
For example, in a button in the MainProject I tried this....
dim m as new MyCommonStuff
x = m.GetInfo()
Intellisense doesn't pick up any of the subs/functions for m. What am I doing wrong? Thanks!
The thing is that you've made your methods static ("Shared" in VB). You need to either remove the Shared keywords:
Public Function GetInfo() As String
':
':
End Function
Public Sub Test()
':
':
End Sub
or keep the Shared keywords and use it like this:
x = MyCommonStuff.GetInfo()
Here is some information about Shared members. Most notably:
Specifies that one or more declared programming elements are
associated with a class or structure at large, and not with a specific
instance of the class or structure.
In other words, if you want to use your methods from an instance of your MyCommonStuff class, e.g. m in m.GetInfo(), you need to leave the Shared keyword off. If, on the other hand, you have a method that is common across all instances of your class or for which you don't even need an instance, you would use the Shared keyword and access the method like I said above, e.g. MyCommonStuff.GetInfo().
Make sure you're importing you common stuff's namespace.

How would I declare a global variable in Visual Basic?

I want to create a variable that can be used across multiple forms.
It's going to be a temporary storage place for integers.
There are a couple of ways to do this in VB: a VB-specific way and a non-VB specific way (i.e. one that could also be implemented in C#.
The VB-specific way is to create a module and place the variable in the module:
Public Module GlobalVariables
Public MyGlobalString As String
End Module
The non-VB-specific way is to create a class with shared properties:
Public Class GlobalVariables
Public Shared Property MyGlobalString As String
End Class
The primary difference between the two approaches is how you access the global variables.
Assuming you are using the same namespace throughout, the VB-specific way allows you to access the variable without a class qualifier:
MyGlobalString = "Test"
For the non-VB-specific way, you must prefix the global variable with the class:
GlobalVariables.MyGlobalString = "Test"
Although it is more verbose, I strongly recommend the non-VB-specific way because if you ever want to transition your code or skillset to C#, the VB-specific way is not portable.
IN VB6 just declare on top code
public GlobalVariable as string
then you can use GlobalVariable in any form as you like.
like
GlobalVariable = "house"
then you can use /call in other form
text1 = GlobalVariable
will show value "house"
You can just add it as PUBLIC to ANY Module
Example:
Module Module1
'Global variables
Public glbtxtTemplateName As String 'GLOBAL VARIABLE FOR TEMPLATE
VB loads the Modals first as a class and all PUBLIC items therein are shared directly. Think about it this way.
Lets say we have a MODULE called "MY_PROCESSES"
When you declare a SUB or a FUNCTION in "MY_PROCESSES" if you want it to be used OUTSIDE of "MY_PROCESSES" you declare as PUBLIC like this
PUBLIC SUB LOAD_TEMPLATE()
....
To get to LOAD_TEMPLATE you just call it in your code from anywhere:
LOAD_TEMPLATE
So if I need to set or use the global variable that I made public in my module I just refer to it by name:
glbtxtTemplateName="TEMPLATE_NAME"
IF glbtxtTemplateName="" then LoadTemplate
I do like building the class as above because you can reference it faster without remembering the variable but if you only need 1 or 2 global variables you can name them like we used to with Hungarian Notation style name.
This method is really quite simple and elegant. Old is new and New is Old.

Using NSubstitute with a vb.net module

We have some existing static methods that are grouped in VB modules.
I want to introduce unit testing to the company, and am looking into using NUnit and NSubstitute.
I can't seem to create a Substitute for the VB module I want to test, or find any examples of how to do this. I am trying to do something like:
Dim Sub = Substitute.For(MyModule)()
but VB tells me 'MyModule is a type and cannot be used as an expression'.
If I try
Dim Sub = Substitute.For(Of MyModule)()
VB tells me 'Module 'MyModule' cannot be used as a type'.
Have I got the syntax wrong or am I trying to do something stupid?
It is not appropriate to unit test Modules and Shared methods (static classes and methods in C#) with a mocking framework because:
Modules (static classes in C#) cannot:
inherit from base classes
implement interfaces
and thus, be mocked
Shared methods (static methods in C#) in mocked instances cannot be called
So, to unit test a Module or a class with Shared methods you need to do so directly. Example: (Unit test attributes omitted...)
Public Class A
Public Shared Function Go(a As Integer) As Integer
Return a + 10
End Function
End Class
Public Class TestClass
Public Sub Test()
Assert.AreEqual(A.Go(5), 15)
End Sub
End Class
make sure your sending in an interface and I wouldn't use a variable name as Sub as it's a reserved type.
Example
Dim fakeWebRequestService = Substitute.For(Of IWebRequestService)()

How can I access variables in another class without deleting others?

I have been charged with porting a VB6 project into VB.NET. In vb6, if you were in a class separate to a particular variable, you could access that variable easily:
Public Class Foo
Public k As Integer
End Class
Public Class Bar
k = 12
End Class
In VB.NET, my understanding is that before you can use a variable in another class, you must declare a new instance of it:
Dim foobar As New Foo
This would be fine, but I have to access these variables from different classes and every time I declare a new instance, it wipes all old values from the variables, which I need. Can anybody help? I tried using Inherits statements but they presented many problems.
Thanks.
Nick
Your're looking for the shared keyword. This makes the member available to other classes without having to have an instance of your class. See MSDN for more info
For the port just use Public module like you would in vb6
Public Module Foo
Public k As Integer
End Module
Public Module Bar
Foo.k = 12
End Module
Its not good practice but it will help you do your first pass at the port. Ideally you would refactor out modules/shared functions as being able to access variable from any part in the system will produce code that is harder to maintain
Dim YourobjName As YourClassName = Me.DataContext
Now you can use public methods and functions with YourobjName. Here YourClassName will be the class you want to access the public objects.