Vb.net: Calling a Function That Does not Match Prototype Passes Compiler Check - vb.net

I have encountered something I would like explained. I have a function InitializeValues() that sets up a combobox, and sets the datasource to a datatable. The datatable is retrievedfrom an instance of the class DGVMain_Functions using the public method GetFileSourceData which takes no parameters.
The issue is that a call to GetFileSourceData(MyConnectionString) will actually compile and run. A run time error occurs when the datatable is returned and attempted to set to the datasource of the cbo. The normal call GetFileSourceData() works properly.
I had asked another developer about this, and he thought I had some stale reference, so I cleaned the project, then deleted everything in my debug folder, and rebuilt, but it still had the same behavior.
My question is this, Why does the compiler accept this and not throw a syntax error, and furthermore why does it even get to the point where you can actually step into this function that should not exist, and have it fail on return?
EDIT: Putting Option Strict On, does make the compiler catch this. "Option Strict On disallows implicit conversions from 'String' to 'Integer'. But that is still not the error I want to see. I would like to know why it does not display something along the lines of "No such overload/definition of that function exists".
The error is this:
An error occurred creating the form. See Exception.InnerException for details. The error is: ERROR: ERROR: Conversion from string "user id=XXXX;data source=XXXXX" to type 'Integer' is not valid.Microsoft.VisualBasicFileProcessor.
"InnerException = {"Input string was not in a correct format."}"
Private Sub InitializeValues()
cboFileSource.DisplayMember = "filesource"
cboFileSource.ValueMember = "filesource"
'first call works fine since it matches
cboFileSource.DataSource = DgvMain_functs.GetFileSourceData()
'below is the call that gets through the complier and actually runs, fails on return
cboFileSource.DataSource = DgvMain_functs.GetFileSourceData(MyConnectionString)
End Sub
Public Function GetFileSourceData() As DataTable
Try
Dim dt As DataTable
Dim strSQL As String = "select distinct filesource from FileUpload_FolderPath"
dt = SqlHelper.ExecuteDataset(MyConnectionString, CommandType.Text, strSQL).Tables(0)
Return dt
Catch ex As Exception
Throw New Exception("Error in DGVMain_Functions: " & ex.Message & ex.Source)
End Try
End Function

As you've hinted in your comment, surely Option Explicit On would solve this issue.

Related

BluetoothLEDevice.FromIdAsync Returns Uncastable __ComObject

Before we even start: In researching this problem I've looked at dozens of posts here and elsewhere, and realize that VB is the worst for Bluetooth programming. However, this is for a client who has a massive legacy VB system and I have no choice.
According to MS documentation, the BluetoothLEDevice.FromIdAsync is supposed to return a BluetoothLEDevice object but on my system it returns a generic System.__ComObject that I can't cast to a BluetoothLEDevice. I have tried Cast and DirectCast but neither work. The sample C++ code I've looked at doesn't require any type of casting; the variable is declared and set using the BluetoothLEDevice.FromIdAsync function without any dramas.
Here is my test code.
Private Sub ConnectToDevice(di As DeviceInformation)
'
' di.id = "BluetoothLE#BluetoothLE48:5f:99:3c:fd:36-84:2e:14:26:9e:7b"
'
Debug.Print("Connecting To " & di.Name & " at " & Now.ToShortTimeString)
Dim genericObject As Object
Dim myDevice As BluetoothLEDevice
Try
genericObject = BluetoothLEDevice.FromIdAsync(di.Id)
Catch ex As Exception
Debug.Print(ex.Message)
End Try
If Not IsNothing(genericObject) Then Debug.Print("Using 'Object' yeilds " & genericObject.ToString)
Try
myDevice = BluetoothLEDevice.FromIdAsync(di.Id)
Catch ex As Exception
Debug.Print(ex.Message)
End Try
End Sub
And here is the output:
Connecting To TM-2021090161 at 2:08 PM
Using 'Object' yeilds System.__ComObject
Exception thrown: 'System.InvalidCastException' in testBTLE.exe
Unable to cast object of type 'System.__ComObject' to type 'Windows.Devices.Bluetooth.BluetoothLEDevice'.
And a screen shot of the returned genericObject:
The FromIdAsync needs to be run async which I couldn't do because I got an error stating it didn't have an awaiter. It turns out that I needed to NuGet the System.Runtime.Windowsruntime dll. I added the Await and it's working now.
Thanks to Andrew for pointing me in the right direction.

Constructor in VBA - Runtime error 91 "Object variable not set"

I am trying to write some code in excel VBA using the Object Oriented Concept. Therefore I wanted to initialize my objects with constructors, like we usually do in Java. However I discovered that the default Class_Initialize() Sub that is offered in VBA does not take arguments. After searching a bit, I found that the answer for this Question proposed a pretty good alternative.
Here is a sample of my Factory Module (I Named it Creator):
Public Function CreateTool(ToolID As Integer) As cTool
Set CreateTool = New cTool
CreateTool.InitiateProperties (ToolID) '<= runtime error 91 here
End Function
The class cTool:
Private pToolID As Integer
Private pAttributes As ADODB.Recordset
Private pCnn As ADODB.Connection
Public Sub InitiateProperties(ToolID As Integer)
Dim sSQL As String
Set pCnn = connectToDB() 'A function that returns a connection to the main DB
pToolID = ToolID
sSQL = "SELECT Tool_ID, Status, Type, Tool_Number " _
& "FROM Tool WHERE Tool_ID = " & pToolID
pAttributes.Open sSQL, pCnn, adOpenKeyset, adLockOptimistic, adCmdText
End Sub
This is how I call the constructor:
Dim tool As cTool
Set tool = Creator.CreateTool(id)
My issue is that when I run the code, I get the following error:
Run-Time error '91' : Object Variable or With Block Variable not Set
The debug highlights the CreateTool.InitiateProperties (ToolID) line of my CreateTool Function.
I know that this usually happens when someone is setting a value to an object without using the keyword Set but it does not seem to be my case.
Any help, advice to resolve this issue would be greatly appreciated!
Thanks.
Might not be the cause of your error, but this:
Public Function CreateTool(ToolID As Integer) As cTool
Set CreateTool = New cTool
CreateTool.InitiateProperties (ToolID) '<= runtime error 91 here
End Function
Is problematic for a number of reasons. Consider:
Public Function CreateTool(ByVal ToolID As Integer) As cTool
Dim result As cTool
Set result = New cTool
result.InitiateProperties ToolID
Set CreateTool = result
End Function
Now, looking at the rest of your code, you're doing the VBA equivalent of doing work in the constructor, i.e. accessing database and other side-effects to constructing your object.
As #Jules correctly identified, you're accessing the unitialized object pAttributes inside InitiateProperties - that's very likely the cause of your problem.
I'd strongly recommend another approach - if you come from Java you know doing work inside a constructor is bad design... the same applies to VBA.
Get your code working, and post it all up on Code Review Stack Exchange for a full peer review.

How to re-write Redundant Assignment?

I have this code:
If SalaryCbx.Checked = True Then
fundSalary = "S" <- Throws an error
Else
fundSalary = "N" <- Throws an error
End If
SonarQube throws a "Critical" error:
Assignment is not used
(Category: Redundancies in Code)
resharper-vbnet RedundantAssignment
Value assigned is not used in any execution path
Is there a better way to write this kind of logic?
I tried a Select Case statement but it also threw the error.
I also use this same code except for different variables/checkboxes and it works fine - no errors.
Update: Here's where I am using it.
Dim insertQry As String = "INSERT INTO FUND (FUND_ID, FUND_NM, FUND_TICKER_NM, FUND_SALARY_IND, FUND_BONUS_IND, FUND_ALCTN_IND, BEG_DT, END_DT) "
insertQry &= " VALUES(#FundID, #fndName, #fndTicker, #fndSalary, #fndBonus, #fndAllocation, #fndBeg, #fndEnd) "
'Code omitted
'Declare Connection String
Using sqlConnection As New SqlConnection(myConn)
'Declare variable for SQL command
Using cmd As New SqlCommand(insertQry)
With cmd
.Connection = sqlConnection
.CommandType = CommandType.Text
.Parameters.AddWithValue("#FundID", id)
.Parameters.AddWithValue("#fndName", fundName)
.Parameters.AddWithValue("#fndTicker", fundTicker)
.Parameters.AddWithValue("#fndSalary", fundSalary)
The message is saying that you're not reading the assigned value in any other part of your code. Possible reasons:
You made an mistake (like a copy-and-paste error) and are accidentally reading a different variable where you intend to read this one.
The reading code has shadowed the written variable with an identically-named variable in a narrower scope.
Old code that no longer needs to be present because nothing is meant to read the variable.
False positive in the checker.

Lambda doesn't close over object in With statement [duplicate]

Just thought I'd share this in case anyone else has run into this.
I did something similar today and it took me a while to figure out why this was causing a problem at runtime.
This code:
Public Class foo
Public bar As String = "blah"
End Class
Public Sub DoInline()
Dim o As New foo
Dim f As Func(Of String)
With o
f = Function() .bar
End With
Try
Console.WriteLine(f.DynamicInvoke())
Catch ex As Reflection.TargetInvocationException
Console.WriteLine(ex.InnerException.ToString)
End Try
End Sub
Throws a NullReferenceException. It seems as though the With is using the closure as its temp storage, and at the "End With", it sets the closure's variable to Nothing.
Here is that code in RedGate Reflector:
Public Shared Sub DoInline()
Dim o As New foo
Dim $VB$Closure_ClosureVariable_7A_6 As New _Closure$__1
$VB$Closure_ClosureVariable_7A_6.$VB$Local_VB$t_ref$L0 = o
Dim f As Func(Of String) = New Func(Of String)(AddressOf $VB$Closure_ClosureVariable_7A_6._Lambda$__1)
$VB$Closure_ClosureVariable_7A_6.$VB$Local_VB$t_ref$L0 = Nothing
Try
Console.WriteLine(RuntimeHelpers.GetObjectValue(f.DynamicInvoke(New Object(0 - 1) {})))
Catch exception1 As TargetInvocationException
ProjectData.SetProjectError(exception1)
Console.WriteLine(exception1.InnerException.ToString)
ProjectData.ClearProjectError
End Try
End Sub
Notice the
$VB$Closure_ClosureVariable_7A_6.$VB$Local_VB$t_ref$L0 = Nothing
Only "question" I can really ask is; is this a bug or a strange design decision that for some reason I'm not seeing.
I'm pretty much just going to avoid using "With" from now on.
This behavior is "By Design" and results from an often misunderstood detail of the With statement.
The With statement actually takes an expression as an argument and not a direct reference (even though it's one of the most common use cases). Section 10.3 of the language spec guarantees that the expression passed into a With block is evaluated only once and is available for the execution of the With statement.
This is implemented by using a temporary. So when executing a .Member expressio inside a With statement you are not accessing the original value but a temporary which points to the original value. It allows for other fun scenarios such as the following.
Dim o as New Foo
o.bar = "some value"
With o
o = Nothing
Console.WriteLine(.bar) ' Prints "some value"
End With
This works because inside the With statement you are not operating on o but rather a temporary pointing to the original expression. This temporary is only guaranteed to be alive for the lifetime of the With statement and is hence Nothingd out at the end.
In your sample the closure correctly captures the temporary value. Hence when it's executed after the With statement completes the temporary is Nothing and the code fails appropriately.
There's really only one bug that I see, the compiler should generate an error for this. Shouldn't be hard to implement. You can report it at connect.microsoft.com

Alternatives to using a Collection class

I have been looking through old code to get familiar with the system I use and found a piece of code that I feel can be used better.
What goes on here is some data gets added to the collection(around 150 string variables, some with two variables(variableName/VariableValue), most with only one(VariableName)). It will try to set a module level string variable to the item of the collection passing it the index(variableName) then if there's a value setting the VariableVAlue to the module level variable.
What I feel needs work is that if the collection is passed a variable and the variable doesn't have a value it will return a "" which would cause a runtime error hence there's a On Error GoTo Handler code to manually add a "" to the collection. I feel there's a better way to do this rather than knowing there will be a runtime issue then solving it after catching it. Would there be a way to have a return "" not throw an exception or would the use of an Array also work here since it's a "collection" as well?
Here's an example to try to help visualize:
Public Function GetCollectionVariable(ByVal varName as string) as String
If collection1 Is Nothing Then
m_collection1 = New Collection
End If
On Error GoTo Handler
GetCollectionVariable = collection1.Item(VarName)
exit function
Handler:
collection1.add("", VarName)
GetCollectionVariable = ""
End FUnction
Thanks for your time!!
If Collection1 is a dictionary, you can use TryGetValue.