Option Strict On disallows late binding in vb.net - vb.net

I'm using COM interface to 3rd part program to get information with my functions. (VS2017 and Framework 4.7.2).
I'm getting an error from Visual Studio: "Option Strict On disallows late binding" for the below function
'x, y, z, al, be, ga. as an array
Protected Friend Shared Function GetComputedBRFPos(ByVal bodyElement As IScrBody, ByVal index As Integer) As Array
Return bodyElement.getComputedBRFPos(p_index:=index)
End Function
It has a documentation at 3rd part tool i'm also writing the description.
VARIANTList getComputedBRFPos ()
Get current BRF position, creates an implicit solver if no solver is existing. Array elements: x, y, z, al, be, ga.
For an example i'm putting another function i'm using and getting no late binding error for below function.
Protected Friend Shared Function Get_sb_node_pos(ByVal bodyElement As IScrBody, ByVal childIndex As Integer) As Array
Return bodyElement.get_sb_node_pos(p_childIndex:=childIndex)
End Function
And it's description at documentation.
VARIANTList get_sb_node_pos (int childIndex)
Get all elements of
sb_node_pos as an array.
I think it causing for bodyElement.getComputedBRFPos(p_index:=index) "index" value but i don't know what's the exact problem and how to achieve.

From the documentation you posted, it seems like bodyElement.getComputedBRFPos doesn't take any parameters. In VB.NET, the () are optional for method without parameters. So your code end up looking like this.
Return bodyElement.getComputedBRFPos()(p_index:=index)
Which doesn't return an array but instead return an element of the array which is of type object.
You should remove the parameter, change the return type or show us the documentation of the method with the parameter you are trying to call.
Return bodyElement.getComputedBRFPos()

Related

Can pass null to generic function when type is a value type

I am currently restricted to using VB.NET using .NET 4.0 and I'd like to use a pre-pending function when I make LINQ queries, here is the function I've created:
<Extension>
Public Iterator Function Prepend(Of TSource)(source As IEnumerable(Of TSource), item As TSource) As IEnumerable(Of TSource)
If source Is Nothing Then Throw New ArgumentNullException(NameOf(source))
Yield item
For Each sourceItem In source
Yield sourceItem
Next
End Function
But the interesting thing is when you pass a null reference when the function is typed to a value type, say Integer:
Dim arr = {1, 2, 3}
Dim arr2 = arr.Prepend(Nothing).ToArray()
This produces an array containing: 0, 1, 2, 3. When converted to the equivalent C# and used in a .NET Core 2.1 project, I correctly receive a compiler error telling me I cannot convert between null and an integer.
Is there a way to tell VB.NET that I do not want this sort of thing to happen and cause an error at compile time or will I need to resort to run-time type checking?
Nothing in VB is not the same as null in C#. The better equivalent is default, because it represents the default value for its type. The behavior is the same for reference types (whose default is a null reference) but very different for value types as you note.
Since this is part of the design of the language, there is no way to turn it off.
Also see Anthony Green's write-up here: https://anthonydgreen.net/2019/02/12/exhausting-list-of-differences-between-vb-net-c/#46

VB.NET - What does ":=" do?

I can't find any information online or under the Operator documentation, but I've seen this ":=" used a few times in VB.NET and I can't work out what it does.
It's used for named parameters (ht to SLaks for the link) in a method call and is usually used with optional arguments.
It's usually useful for calling Word or Excel methods through ActiveX calls, where there are an awful lot of optional arguments, most of which are never used.
Example
Private Function test(arg1 As Integer, arg2 As Integer) As Boolean
Debug.WriteLine("{0} {1}", arg1, arg2)
Return True
End Function
These two will both produce the same result
test(arg2:=2, arg1:=1)
test(1, 2)
Debug output
1 2
1 2
This is used for named parameters:
MyMethod(parameterName := value)
This is to use "named parameters", so you can use parameters in a function in any order, telling the function the name of each one. :)

How do I get a reference to an array back from VB when using IronPython?

I'm not a Python programmer, but I'm trying to get a simple script working using IronPython and VB.Net. I've gotten pretty far, but now I'm stuck on passing arguments by reference. I need to be able to get data back from the VB side into the Python side in the argument list (since Python returns tuples, but .Net doesn't). However, this code doesn't work, and I don't know why not.
Here is the python code:
def GetVoltages(voltages):
fixture.StartScan()
done=False
counter=0
while done == False:
fixture.GetNumDataPoints(num)
if num>=15:
done=True
else:
counter=counter+1
if counter>1000000:
break
if done == True:
fixture.GetDataPoints(num, voltages)
else:
log.WriteLine("Failed to read voltages.")
return done
buff = Array.CreateInstance(System.Double, 0)
if GetVoltages(buff):
log.WriteLine("Checking voltages.")
CheckVoltage(buff, 3, 22)
# do other stuff
fixture is a defined variable, and the function is called correctly, but num and voltages on the python side never change. Here is the function declarations on the VB side:
Public Function GetDataPoints(ByVal num As Integer, ByRef vals() As Double) As Boolean
Public Function GetNumDataPoints(ByRef num As Integer) As Boolean
I've found a couple old pages that give some hints, but I'm not seeing what the right answer is.
Basically, IronPython bundles ref and out parameters into the result as a tuple. That means you want something like:
success, num = fixture.GetNumDataPoints(num)
success, voltages = fixture.GetDataPoints(num, voltages)
There may be some interaction between ref and arrays, but this should work.

Weird equality issue with Generics and Enums?

I'm kind of going nuts here. I have a function something like the following. It's failing to return an object. I can pass in a list, I can see in QuickWatch that x.RB = theRb for at least one of the items in the list, yet it doesn't exit the loop (via the Return). The loop continues.
The list I am passing in is a subclass of aXXX.
Property RB on class aXXX is of type RBEnum.
Also, I originally used Linq for this but was getting "no matching items" exceptions.
Private Shared Function GetX(Of T As aXXX)(ByVal a As List(Of T),
ByVal theRb As RBEnum) As T
For Each x As T In a
If (x.RB = theRb) Then Return x
Next
Return Nothing
End Function
Any suggestions or ideas on why this isn't working?
I would recommend trying:
If (x.RB.Equals(theRb)) Then Return x
Can you cast the Enum into an Integer and then compare?
If CInt(x.RB)=CInt(theRb) Then Return x
I'm not sure how your original where statement was written but this should produce the result you're looking for:
Private Shared Function GetX(Of T As aXXX)(ByVal a As List(Of T),
ByVal theRb As RBEnum) As T
Return a.Where(Function(x) x.RB = theRb).FirstOrDefault()
End Function
I have resolution. I can't fully explain it though.
The list of items I'm passing in are a subclass of the class aXXX. The subclass did not properly override the RB property from the base class -- no Overloads / Overrides / Shadows. This kind of gives explanation as to why QuickWatch reports True on the match -- maybe this subclass property was hiding the "real" property value that was in the test?
Anyway, by taking out the property in the subclass all together or adding an Overloads, the For Each behaves as one would expect. I can even go back to the original Linq version I had in the function.
I guess this came down to oversight / sloppy coding on my part. But the issue was masked pretty well by the fact that QuickWatch reported "false positives"!
Thanks to everyone for the suggestions and help.

How Do I Create Something 'OF' a Variable's Type?

I have some code like:
Lookup(Of String)("Testing")
Lookup(Of Integer)("Testing")
And both of those Lookups work great. What I'm trying to is call the appropriate LookUp based on the type of another variable. Something that would look like...
Lookup(Of GetType(MyStringVariable))("Testing")
I've tried to Google this but I'm having a hard time coming up with an appropriate search. Can anyone tell me how to do what I want?
You do not specify the full signature for the method that you're calling, but my psychic powers tell me that it is this:
Function Lookup(Of T)(key As String) As T
And you want to avoid having to repeat Integer twice as in the example below:
Dim x As Integer
x = Lookup(Of Integer)("foo");
The problem is that type parameters are only deduced when they're used in argument context, but never in return value context. So, you need a helper function with a ByRef argument to do the trick:
Sub Lookup(Of T)(key As String, ByRef result As T)
T = Lookup(Of T)(key)
End Sub
With that, you can write:
Dim x As Integer
Lookup("foo", x);
One solution to this is to use reflection. See this question for details.
You can't use a dynamic type unless you do runtime compiling, which of course is really inefficient.
Although generics allows you to use different types, the type still has to be known at compile time so that the compiler can generate the specific code for that type.
This is not the way to go. You should ask about what problem you are trying to solve, instead of asking about the way that you think that it should be solved. Even if it might be possible to do something close to what you are asking, it's most likely that the best solution is something completely different.
The VB.NET compiler in VS2008 actually uses type-inference. That means if you are using a generic method, and one of the parameters is of the generic type, then you don't need to specify the generic type in your call.
Take the following definition...
Function DoSomething(Of T)(Target As T) As Boolean
If you call it with a strongly-typed String for Target, and don't specify the generic parameter, it will infer T as String.
If you call it with a strongly-typed Integer for Target, and don't specify the generic parameter, it will infer T as Integer.
So you could call this function as follows:
Dim myResult As Boolean = DoSomething("my new string")
And it will automatically infer the type of T as String.
EDIT:
NOTE: This works for single or multiple generic parameters.
NOTE: This works also for variables in the argument list, not just literals.