MustOverride turns out as a Virtual Method? - vb.net

While researching Assembly.GetInterfaces(), I found the method was a MustOverride method. Which in my understanding means it has no default action to derived classes. Its just a signature basically, an abstract method. Yet, I can still use it on a type and it will return all implemented interfaces without writing any code for the MustOverride method.
Where is this code that has slipped into the MustOverride method? Have I somehow indirectly overridden it just simply by calling the method on a created type?
This question is purely on the basis of study and discovery, I am not trying to do anything other than understand the confines of the language.
Here is the code I used:
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim t As Type
Debug.WriteLine(GetType(Integer))
t = GetType(Integer)
Dim interfaceArr As Type() = t.GetInterfaces
For i As Integer = 0 To interfaceArr.Length - 1
Debug.WriteLine(interfaceArr(i))
Next
End Sub
End Class
Output Is:
System.IComparable
System.IFormattable
System.IConvertible
System.IComparable 1[System.Int32]
System.IEquatable 1[System.Int32]

Any MustOverride method can always be called on an instance of any type because you couldn't possibly create an instance of a class unless the class provides concrete implementations of all of the MustOverride methods. In this case, your confusion is that you are assuming that the t variable is referencing a Type object, but that is not the case. Since Type is a MustInherit class, it's impossible to ever instantiate an object of that type directly. You could only ever instantiate an object of a class that derives from Type. If you use the debugger to inspect the T variable, you will notice that it is actually referencing an instance of the RuntimeType class, which is an undocumented class which obviously derives from Type.
For instance, consider this example, which duplicates the behavior:
Public Class Form1
Public MustInherit Class BaseClass
Public MustOverride Function GetGreeting() As String
End Class
Public Class DerivedClass
Inherits BaseClass
Public Overrides Function GetGreeting() As String
Return "Hello world"
End Function
End Class
Public Function GetInstance() As BaseClass
Return New DerivedClass()
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim t As BaseClass = GetInstance()
Debug.WriteLine(t.GetGreeting())
End Sub
End Class
As you can see, the t variable is of the BaseClass type, but it's actually referencing a DerivedClass object. Therefore, even though the BaseClass class defines the method as MustOverride, you can still call it because the actual type of the object does implement it.

Related

vb.net extending a class with generics

is it possible to extend different classes with the same generic class?
I tried something like this:
Public Class A
Public Sub TestA()
Debug.Print("Test A")
End Sub
End Class
Public Class B(Of T)
Public Sub TestB()
Debug.Print("Test B")
End Sub
End Class
Public Class C
Inherits B(Of A)
Public Sub TestC()
TestA() '**<-- Thows error 'is not declared'**
TestB()
Debug.Print("Test C")
End Sub
End Class
I basicly have some usercontrols, which derive from Combobox or Textbox and i'd like both to implement some functions(and interfaces) that are defined in a base class. In C++ i'd do it with multi inheritance.
is it possible to extend different classes with the same generic class?
Generics isn't some kind of "workaround" for a lack of multiple inheritance, no. Your class C doesn't derive from A - it just means that the T in B(Of T) would be A in the context of C.
Which instance of A would you expect TestA() to be called on? Creating an instance of C certainly doesn't create an instance of A...
The fact that B(Of T) doesn't use T anywhere should be a warning signal - types which are generic but never use their generic type parameters are generally problematic.
It's hard to know exactly how to help you solve your real problem without more details, but you can't add a common base class in like this, when you also need to derive from other types which aren't under your control.
Perhaps extension methods would help?
You could make both your Combobox and your Textbox classes implement the same interface.
Then you could define extension methods on that interface class.
Thanks to your hint i got this working with extentions
Public Class Form1
Public Interface IA
Property val As String
End Interface
Public Class A
Public Sub test()
Debug.Print("test")
End Sub
End Class
Public Class C
Inherits A
Implements IA
Public Property val As String Implements IA.val
Public Sub TestC()
val = "testxxx"
TestA()
test()
End Sub
End Class
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim ct As New C
ct.TestC()
End Sub
End Class
Module TestModule
<Extension()>
Public Sub TestA(ByVal pvIA As IA)
Debug.Print(pvIA.val)
End Sub
End Module
This way every class can implement it's own 'parent' (like A here) and i don't need to implement the function TestA for every class.
thank you

Implementing an interface with more general methods

I have this interface:
Public Interface IDocumentSavingEventArgs
Inherits IDocumentCancelEventArgs
Property SuggestedDocName As String
Property SuppressSaveDialog As Boolean
End Interface
which, as shown, inherits from a more general interface IDocumentCancelEventArgs.
Then I have this interface:
Public Interface IDocumentSavingHandlerProvider
Inherits IProvider
Sub DocumentSavingHandler(sender As Object, e As IDocumentSavingEventArgs)
End Interface
For old pulgins compatibility purposes, I need to implement the latter interface also using an e of type IDocumentCancelEventArgs:
Public Sub MySavingHandler(sender As Object, e As IDocumentCancelEventArgs)
Implements IDocumentSavingHandlerProvider.DocumentSavingHandler
This seems not possible, as the compiler warns me that there is no DocumentSavingHandler method with that signature.
At runtime, this should not be an issue, in my opinion, as MySavingHandler would accept an IDocumentSavingEventArgs for sure, since it's typeof IDocumentCancelEventArgs.
Is there a way to achieve this?
As stated before, the compiler is correct. You need to have function signatures which match. I think what may be confusing here is even though you could pass a IDocumentSavingEventArgs to a function accepting IDocumentCancelEventArgs the compiler sees these definitions as two separate functions. If you want something more general, you may have to abstract those interfaces to another interface, which I wouldn't recommend since that gets un-maintainable fairly quickly, or you could create an overloaded function in your interface.
Public Interface IDocumentSavingHandlerProvider
Inherits IProvider
Sub DocumentSavingHandler(sender As Object, e As IDocumentSavingEventArgs)
Sub DocumentSavingHandler(sender As Object, e As IDocumentCancelEventArgs)
End Interface
In the latter function you can convert the object to whatever you need it to be and then pass it to your main DocumentSavingHandler method.
The compiler is correct, since IDocumentCancelEventArgs doesn't inherit from IDocumentSavingEventArgs it can't be cast to IDocumentSavingEventArgs. Then you can test in your implementation if e is IDocumentCancelEventArgs or IDocumentSavingEventArgs.
You need to use the least common denominator IDocumentCancelEventArgs
Public Interface IDocumentSavingHandlerProvider
Inherits IProvider
Sub DocumentSavingHandler(sender As Object, e As IDocumentCancelEventArgs)
End Interface
Public Sub DocumentSavingHandler(sender As Object, e As IDocumentCancelEventArgs) Implements IDocumentSavingHandlerProvider.DocumentSavingHandler
Dim saveEventArgs As IDocumentSavingEventArgs
If TypeOf e Is IDocumentSavingEventArgs Then
saveEventArgs = DirectCast(e, IDocumentSavingEventArgs)
Else
' Do something else....
End If
End Sub

Declare Class Level Variables in Child Class

I would like to declare class level variables for a bunch of child classes similar to this in python: Static class variables in Python. I've learned that the shared attributed is probably what I want to use, but I'm not quite sure where to use it.
Here's my situation: I am making a bunch of different character types for a game (100+). All the character types have the same set of properties, so I've created a base class that includes all of the properties and the required internal variables. Each character type has a set of immutable properties that are exactly the same for every instance of the given character type, but differ between character types. I would like to contain the immutable character type properties as class "variables" in child classes (one child class per character type), like in the answer to the python example above.
The key is I would like to reference some properties WITHOUT having to create an instance of the sub class.
My problem is I can't figure out what needs to be shared to properly do this or how my code needs to be organized to make this happen. I tried sharing the properties which finally allowed me to get to the properties from the child class and not just an instance of the child, but then it wouldn't return the property I assigned in the child class using Shared or Shared Shadows. I would like to keep the properties in the base class so that I don't have to copy and paste the same properties for every child class.
Here is some samples of my code:
Public MustInherit Class Char
'IMMUTABLE INFORMATION
' CharType Traits
Shared _ID As Integer
Shared _Species As String
Public Shared ReadOnly Property Species As String
Get
Return _Species
End Get
End Property
End Class
Public Class CharCat
Inherits Char
Shared Shadows _Species = "Cat"
End Class
The goal is to be able to type CharCat.Species and have it return "Cat". I know this example is redundant with the class name, but for other properties it's not.
You can make the BaseClass Species Property Overridable to achieve what you're looking for.
Public MustInherit Class [Char]
Private _ID As Integer
Private _Species As String
Public Overridable ReadOnly Property Species As String
Get
Return _Species
End Get
End Property
End Class
Public Class CharCat
Inherits Char
Public OverLoads Shared ReadOnly Property Species As String
Get
Return "Cat"
End Get
End Property
End Class
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MsgBox(CharCat.Species)
End Sub
Using NoAlias's response as a spring board in collaboration with more research and SO questions, I've found an complete answer. The base class does NOT need Overridable considering that, since the child class uses Shared, it CAN'T have a Overrides property. Overloads reportedly does nothing to a property according to Hans Passant so we don't need that either.
Now the code works with these two changes but there's a warning flag that says the property should be declared as "Overloads" which isn't actually the proper solution. To properly get rid of the warning, Shadows should be declared. The code worked without declaring shadows because Shadowing is the default behavior for a child property, but in order to get rid of the warning VB throws, you need to declare it explicitly.
The code ends up looking like this:
Public MustInherit Class [Char]
Private _ID As Integer
Private _Species As String
Public ReadOnly Property Species As String
Get
Return _Species
End Get
End Property
End Class
Public Class CharCat
Inherits Char
Public Shared Shadows ReadOnly Property Species As String
Get
Return "Cat"
End Get
End Property
End Class
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
MsgBox(CharCat.Species)
End Sub
It's important to note that we now have to deal with the Shadows behavior. If a child class is called through the parent class, you'll get parent class behavior for the property. For me, since I couldn't use Overrides because I'm using Shared, I decided the best way to avoid the parent class behavior was to just get ride of the parent class property since it wasn't holding any important information anyways. You could try be super careful not to call a child through the parent in your code to avoid the parent behavior as well.

VB.NET interface

I understand the concept of interfaces, however I often find it difficult to find practical examples of how to use them. I have produced the following code:
Public MustInherit Class Deletion2
Implements DeletionInterface2
Public MustOverride Function Delete() As String Implements DeletionInterface2.Delete
Public Function CheckDate() As Boolean Implements DeletionInterface2.CheckDate
Return True
End Function
End Class
Public Class System1Delete
Inherits Deletion2
Implements DeletionInterface2
Overrides Function Delete() As String
Return "System 1 Deleted"
End Function
End Class
Public Class System2Delete
Inherits Deletion2
Implements DeletionInterface2
Overrides Function Delete() As String
Return "System 2 Deleted"
End Function
End Class
Public Interface DeletionInterface2
Function CheckDate() As Boolean
Function Delete() As String
End Interface
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim IDeletion As DeletionInterface2
IDeletion = New System1Delete
IDeletion.CheckDate()
IDeletion.Delete()
IDeletion = Nothing
IDeletion = New System2Delete
IDeletion.CheckDate()
IDeletion.Delete()
IDeletion = Nothing
End Sub
In the example above (in page load) I have used a reference to an interface to create an instance of an object, but I do not understand the true benefit of this.
The benefit of using an abstraction like an interface (or a MustInherit class) is that you can treat any object that implements the interface the same exact way.
For example, the System.Data namespace uses many such abstraction, meaning that implementing the different data providers is easier and since the core is using these abstractions, it doesn't need to change as new implementations are added (things about all the different providers, built in and third party - SQL Server, Oracle, PostGresSQL, MySQL etc...).

Sub to create object of type passed by caller in VB.NET

I'm having trouble creating a sub that can create objects of a variable type on the fly. Here's an example of what I'm trying to achieve:
class systemSettings
'some properties
end class
Class fireSystemSettings
inherits systemSettings
'some additional properties
end class
Class windSystemSettings
inherits systemSettings
'some additional properties
end class
sub createSystem(systemType as Type, arg1 as object, arg2 as object)
Dim newSystem as New systemType(arg1, arg2)
systemCollection.add(newSystem)
end sub
I can't get it to work. I've done a fair bit of research, and looked at generic types, reflection, and other tools, but I'm having trouble determining how best to tackle this problem.
You're looking for Activator.CreateInstance(systemType)
Use generics for this:
Sub createSystem(Of T As {New, systemSettings})()
Dim newSystem As New T
systemCollection.add(newSystem)
End Sub
And call it with:
createSystem(Of windSystem)
To explain:
The term Of T lets you create a method that can be used for any type. Every time you call it for a new value of T, a new method is created in memory.
The term As {New, systemSettings} constrains T. It says that T must represent a type that is or derives from systemSettings. It also says that T must contain a default constructor: New() which is required for the command New T. Note that you cannot specify a more elaborate constructor as a generics constraint.
If you require parameters in your constructor, you can create an Initialise method in the base class. Because T is constrained to systemSettings, it is guaranteed that the Initialise method exists.
Class systemSettings
Public Overridable Sub Initialise(arg1 As Object, arg2 As Object)
'initialise properties
End Sub
'some properties
End class
Class fireSystemSettings
Inherits systemSettings
Public Overrides Sub Initialise(arg1 As Object, arg2 As Object)
'initialise properties
End Sub
'some additional properties
End Class
Class windSystemSettings
Inherits systemSettings
Public Overrides Sub Initialise(arg1 As Object, arg2 As Object)
'initialise properties
End Sub
'some additional properties
End Class
Sub createSystem(Of T As {New, systemSettings})(arg1 As Object, arg2 As Object)
Dim newSystem As New T
newSystem.Initialise(arg1, arg2)
systemCollection.add(newSystem)
End Sub