Why this sub is valid? Why i can pass each Type (String, Interface, Int) to a sub without compiler error as parameter - vb.net

Public Class MainWindow
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Me.x(1)
End Sub
Public Sub x(ByVal x As String)
MessageBox.Show(x)
End Sub
End Class
If I want a Interface in sub x as example Public sub x(Byval IPerson) it also accept every type without an error.

In VS2013 under Debug/Debugging/Projects and Solutions/VB Defaults is an option to turn Option Strict to on.

Related

Collect Generic Delegates in a Dictionary

I try to collect generic delegates in a dictionary. I made a little example, knowing that this example doesn't make sense. When I try to add the delegate to the dictionary I get a implizit conversion warning and I don't know how to solve this.
This is the line which shows the warning:
m_MyDoSomethings.Add(1, AddressOf myCustomDoSomething)
Hint: You have to activate implizit conversion warnings in your project, otherwise you won't get this error. It is a implizit conversion error, which tells me that it is not possible to convert the type "BaseDoSomething" to "CustomDoSomething". I don't understand why he is converting this way and not backwards.
Public Class Form1
Private Delegate Sub DoSomethingDelegate(Of T As BaseDoSomething)(p_DoSomethingClass As T)
Private m_MyDoSomethings As New Dictionary(Of Short, DoSomethingDelegate(Of BaseDoSomething))
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
m_MyDoSomethings.Add(1, AddressOf myCustomDoSomething)
End Sub
Private Sub myCustomDoSomething(p_CustomDoSomething As CustomDoSomething)
p_CustomDoSomething.echo()
p_CustomDoSomething.echo2()
End Sub
End Class
Public Class BaseDoSomething
Public Overridable Sub echo()
MsgBox("echo")
End Sub
End Class
Public Class CustomDoSomething
Inherits BaseDoSomething
Public Overrides Sub echo()
MsgBox("custom echo")
End Sub
Public Sub echo2()
MsgBox("hello world")
End Sub
End Class

How do I get an event to fire as soon as an object's constructor has finished?

Research tells me that raising an event from the constructor itself is not feasible as the object may not be fully initialised... so where can I fire an event from as soon as the constructor has fired?
One thing you can do is add a method to handle additional post ctor tasks:
Friend Class FooBar
Public Sub New
' your code here
End Sub
Public Sub Create
' do anything you want
End Sub
End Class
Elsewhere:
Friend WithEvents Foo As Foobar
' ...
Foo = New FooBar ' Foo doesnt exist until ctor code executes and the
' code returns to here.
Foo.Create ' do whatever you like, as long as any other
' objects referenced have been created.
The reason calling a sub from the ctor to raise an event wont work with a class is this:
Private Sub SomeEvent(sender As Object, e As EventArgs) Handles Foo.SomeEvent
Console.Beep()
End Sub
the key is Handles Foo.SomeEvent
There is no Foo yet to handle the event. It doesnt crash and there event is raised, but there is no object for the listener to catch/handle the event. Enough of a form is created in InitializeComponents, that it does work with a form.
There might also be an Interface to implement something like this, I know of some for Components, but not classes.
You could use the Load or Show events from the Shown.
Private Sub myForm_Shown(sender As Object, e As EventArgs) Handles Me.Shown
End Sub
or
Private Sub myForm_Load(sender As Object, e As EventArgs) Handles Me.Load
End Sub
You can accomplish this by adding an Action(Of T) parameter to your constructor and invoke the delegate on the very last line.
Public Class Foo
Public Sub New(ByVal action As Action(Of Foo))
'...
'...
'...
If (Not action Is Nothing) Then action.Invoke(Me)
End Sub
End Class
Example
Public Class Form1
Private Sub Button1_Click(sender As Object, ev As EventArgs) Handles Button1.Click
Dim foo1 As New Foo("foo1", AddressOf Me.HandleFooCtor)
Dim foo2 As New Foo("foo2", Sub(f As Foo) MessageBox.Show(f.Name))
End Sub
Private Sub HandleFooCtor(f As Foo)
MessageBox.Show(f.Name)
End Sub
Public Class Foo
Public Sub New(name As String, Optional ByVal action As Action(Of Foo) = Nothing)
'...
'...
'...
Me.Name = name
If (Not action Is Nothing) Then action.Invoke(Me)
End Sub
Public ReadOnly Name As String
End Class
End Class

Form cannot refer to itself through its default instance on shared call

Consider the following code, in a brand new WinForms .NET 4.0 application, with default settings:
Public Class Form1
Private Sub AAA()
Form1.AAA(Nothing) 'cannot refer to itself through its default instance; use 'Me' instead.
End Sub
Private Shared Sub AAA(str As String)
End Sub
End Class
I am getting this error:
{FORM_CLASS_NAME} cannot refer to itself through its default instance; use 'Me' instead.
I also get this warning at the same line:
Access of shared member, constant member, enum member or nested type through an instance; qualifying expression will not be evaluated.
Assuming default instance is meant here, it ends up in an infinite loop - VS suggests to change Me.AAA() to Form1.AAA(), and then back. AAA() works in both.
Converting Private Sub AAA() to Shared solves the error. It seems like from Microsoft's point of view, all overloads must be shared, if at least one is. Or you get this default instance confusion. Why?
To clarify, I do not want to use default instance here, just do a shared call.
If anyone encountered the same situation, please advise.
Creating a variable alias that has the same name as the type of the Form class is without a doubt the single most disastrous VB.NET problem. But it was necessary to give VB6 developers a fighting chance to move to VB.NET.
The workaround is to stop trying to be explicit about what method you want to call. This compiles fine and is unambiguous, at least in your snippet:
Private Sub AAA()
AAA(Nothing) '' fine
End Sub
If that really, really hurts then simply swapping the two methods removes the ambiguity:
Private Shared Sub AAA(str As String)
End Sub
Private Sub AAA()
Form1.AAA(Nothing) '' fine
End Sub
Can you get away with this? Your usage will be very similar Form1.AAA() vs. code.AAA().
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
code.AAA()
End Sub
Private Class code
Public Shared Sub AAA()
End Sub
End Class
End Class
EDIT
Given the new information in the OP - another solution to your issue may be to use optional parameters -- ie :
Private Shared Sub AAA(Optional ByVal str As String = Nothing)
Also - the resolution works out in the "right" way if you simply change the ordering of the declarations -- this avoids the compiler error:
Private Shared Sub AAA(ByVal str As String)
End Sub
Private Sub AAA()
Form1.AAA(Nothing)
End Sub
--
Keeping this below because it can be helpful in other circumstances
Perhaps your larger application did something like this - VB is full of messes like this you can get yourself into. This will compile but it will crash :
Public Class Form1
Private Shared Sub AAA()
Form1.Text = "this"
End Sub
Private Sub Label1_TextChanged(sender As System.Object, _
e As System.EventArgs) _
Handles Label1.TextChanged
Form1.AAA()
End Sub
End Class
Just the same, this actually is "fine" (I use the term loosely)...
Public Class Form1
Private Shared dont As Boolean = True
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) _
Handles MyBase.Load
dont = False
End Sub
Private Shared Sub AAA()
If Not dont Then Form1.Text = "this"
End Sub
Private Sub Label1_TextChanged(sender As System.Object, _
e As System.EventArgs) _
Handles Label1.TextChanged
Form1.AAA()
End Sub
End Class
This is because the text changed handler will fire before Form1 completes loading (ie : during InitializeComponent()!) and will refer to the default instance which is not yet finished being created - so VB tries to create a new one for you so that you can call the shared method which spins you down the infinite loop.
Oddly, the Load handler is "fine" (again, loosely) to call Form1.AAA() in - as in your opening code - because the default instance (Form1 the instance of Form1 the Class) is finished creation at that point and another won't be created to satisfy the call. Any other code path, however, that starts in the shared call and ultimately ends up touching any instance data, no matter how torturous the path, will loop around and crash.
See also : Why is there a default instance of every form in VB.Net but not in C#?
Unclear what you are trying to accomplish overall. In the OP Form1.AAA should be just AAA.
Private Sub AAA()
AAA(Nothing)
End Sub
Private Sub AAA(str As String)
If str IsNot Nothing Then MsgBox(str) ' else ???
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
AAA()
AAA("hello")
End Sub

Do Delegate arguments Need to Match Event Signature?

Please have a look at the code below:
Public Delegate Sub TestButtonClick(ByVal test As Integer)
Public Class Person
Private Name As String
Private ID As Integer
Public Event ButtonClick As TestButtonClick
Public Sub DelegateTest1(ByVal Test As Integer)
MsgBox(Test)
End Sub
Public Sub ChangeName()
RaiseEvent ButtonClick(1)
End Sub
Public Sub DelegateTest2()
MsgBox("Delegate Test 2")
End Sub
Public Sub DelegateTest3()
MsgBox("Delegate Test 3")
End Sub
End Class
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim p1 As Person = New Person
AddHandler p1.ButtonClick, AddressOf p1.DelegateTest1
AddHandler p1.ButtonClick, AddressOf p1.DelegateTest2
AddHandler p1.ButtonClick, AddressOf p1.DelegateTest3
p1.ChangeName()
End Sub
End Class
The output is:
1
DelegateTest2
DelegateTest3
I do not understand why this application compiles i.e. the delegate accepts an integer in its signature but Person.DelegateTest2 and Person.DelegateTest3 do not.
If I change Person.DelegateTest2() to the following then I do get an error as I would expect:
Public Sub DelegateTest2(ByVal Test As Integer, ByVal Test2 As Integer)
MsgBox("Delegate Test 2")
End Sub
Why does the Delegate allow you to pass zero arguments when it has arguments i.e. an integer in my case?
Don't forget that VB.NET inherits all the legacy baggage from the beloved VB. You could make it strict by putting the following to the top of your file so that it behaves as a real .NET programming language and not some hybrid crap:
Option Strict On
Also I would recommend you setting this to be the default option so that you don't find yourself in the wilderness.

Calling Private Functions from combobox

I need to build an application that could run code in private function, based on what user has selected using combobox.
For example combo box has three values, One, Two, Three
If user selects one, code written under Private Function One() runs and vise versa
Thanks
Furqan
An easier way would be to assign a function for when the combo box is selected. Inside your function have a select statement like: (Pesduo)
Function comboSelected
Case "One"
call Onefunction()
Case "Two"
call Twofunction()
End function
Why are you declaring these as private?
Form controls cannot access private functions. You should declare them as protected.
Here's a way to make it work - assuming Windows Forms.
First, define this class:
Public Class ComboAction
Public Sub New(ByVal text As String, ByVal action As Action)
_text = text
_action = action
End Sub
Private _text As String
Public ReadOnly Property Text() As String
Get
Return _text
End Get
End Property
Private _action As Action
Public ReadOnly Property Action() As Action
Get
Return _action
End Get
End Property
Public Overrides Function ToString() As String
Return Me.Text
End Function
End Class
Now create a form like this:
Public Class ComboActionForm
Private Sub ComboActionForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.ComboBox1.Items.Add(New ComboAction("Show Foo", AddressOf Foo))
Me.ComboBox1.Items.Add(New ComboAction("Show Bar", AddressOf Bar))
End Sub
Private Sub Foo()
System.Windows.Forms.MessageBox.Show("Foo")
End Sub
Private Sub Bar()
System.Windows.Forms.MessageBox.Show("Bar")
End Sub
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
CType(Me.ComboBox1.SelectedItem, ComboAction).Action.Invoke()
End Sub
End Class
You can add as many ComboAction classes to the ComboBox as you wish. Each can have any Action you define - private methods or otherwise. The sky is the limit. :-)
See my another post. This works great!