Is it possible to overload the array/dict access operators in VB.net? For example, you can state something like:
Dim mydict As New Hashtable()
mydict.add("Cool guy", "Overloading is dangerous!")
mydict("Cool guy") = "Overloading is cool!"
And that works just fine. But what I would like to do is be able to say:
mydict("Cool guy") = "3"
and then have 3 automagically converted to the Integer 3.
I mean, sure I can have a private member mydict.coolguy and have setCoolguy() and getCoolguy() methods, but I would prefer to be able to write it the former way if at all possible.
Thanks
To clarify - I want to be able to "do stuff" with the value. So for instance, say I have
myclass.fizzlesticks ' String type
myclass.thingone ' Numerical type, say integer
and then I want to be able to write
myclass("thingummy") = "This is crazy"
which fires off a method that looks like this
Private sub insanitea(Byval somarg as Object, Byval rhs as Object)
If somearg = "thingummy" And rhs = "This is crazy" Then
thingone = 4
fizzlesticks = rhs & " and cool too!"
End If
End Sub
This isn't the precise use-case, but I think it does a better job of being able to illustrate what I'm looking for?
No, you can't overload the array access operators in Visual Basic.
Currently the only operators you can overload are:
Unary operators:
+ - Not IsTrue IsFalse CType
Binary operators:
+ - * / \ & Like Mod And Or Xor
^ << >> = <> > < >= <=
Why can't you do the following:
mydict("Cool guy") = 3 //without quotes
Then you can do
dim x = mydict("Cool guy") + 7
//x returns 10
Or, you could do a Int32.tryParse
dim x as integer
if int32.tryParse(mydict("Cool guy"), x) then
return x + 7 //would return 10
end if
Related
Suppose I've got a couple of classes, like class1 and class2. These classes can have many properties and they can even change from an execution to another (depending on the version of the software).
The user can define a "formula" in plain text and the software should convert the names of the "variables" (class+property) with their actual values. So, given an instance of class1 and an instance of class2, I should cycle the properties (and variables) and check if the formula contains them. For each one I should then replace the name with the value.
For example, I could have:
Dim myClass1 As Class1 = New Class1()
myClass1.PropertyA = "FOO"
myClass1.PropertyB = 5
Dim myClass2 As Class2 = New Class2()
myClass2.PropertyX = "BAR"
myClass2.PropertyY = 7
And the user could have declared this formula (the formula here is simplified in VB.NET, but actually it can be in SQL or different type. The formula is in plain text, so is a string in code):
Dim i = 0
While (i + myClass1.PropertyB) < myClass2.PropertyY
str = "myClass1.PropertyA" & "myClass2.PropertyX"
i += 1
End While
The result, after the replace, should be:
Dim i = 0
While (i + 5) < 7
str = "FOO" & "BAR"
i += 1
End While
Now, the classes and the variables can vary, so I can't search for specific strings. I think I should use reflection, but I'm not used to it and I prefer to avoid it if a better solution exists. Any advice and/or best practice?
This can be done as a class or as a function
Consider the formula.
x=(aa)+(bb)+(2*a*b)
Public Function formularesult(Byval a1 as double,Byval b1 as double) as double
Dim x as double
x=0
Dim a as double
a=0
Dim b as double
b=0
a =a1
b=b1
x=(a*a)+(b*b)+(2*a*b)
return x
End Function
Call to the function can bs follows
Let values of a and b can be 12 and 20 respectively.
Dim result as double
result =formularesult(12,20)
I hope this can be a help for someone.
Improvements to my suggestions are always welcome.
i m working on translating code from VB to C#, though there are lots of great conversion websites, i still find the code ambiguous to me, since the documentation is really poor it approaches to useless, i thought about posting it here to see if i can get it clearer.
i need some elaboration on the code given below, and whats the use of the Buffer[] in the method below:
Function hexToBin(ByVal str As String, ByRef Buffer() As Byte)
Dim strRemain As String
Dim firstChar As Boolean
Dim i, count, inputLen, remainLen As Integer
i = 0
count = 0
firstChar = True
strRemain = str
While Len(strRemain) > 0
If Mid(strRemain, 1, 1) = " " Then
firstChar = True
strRemain = Mid(strRemain, 2)
ElseIf firstChar = True Then
If Len(strRemain) = 1 Then
Buffer(count) = myVal(strRemain)
ElseIf Len(strRemain) >= 2 Then
Buffer(count) = myVal(Mid(strRemain, 1, 1)) * 16 + myVal(Mid(strRemain, 2, 1))
strRemain = Mid(strRemain, 3)
End If
count = count + 1
firstChar = False
Else
strRemain = Mid(strRemain, 2)
End If
Wend
hexToBin = count
End Function
see, i know this code converts from hex to binary as the name suggests, yet i cant really figure the use of the Buffer[] in the context, i looked up the Mid function in string VB, but still can't figure out the use of the Buffer[] in this function, i would appreciate if someone explained the use of the buffer.
In the code above, the parentheses are used to access elements of an array. So, Buffer(i) refers to the ith element of the array Buffer.
You can learn more about arrays in VB from any text book, or indeed from MSDN: http://msdn.microsoft.com/en-us/library/wak0wfyt.aspx
As for why the array Buffer is used in the first place, well that's to store the output of the function. The function takes a hex string as input and populates the byte array Buffer with the binary equivalent.
This does seem to be rather inefficient code though. And it presents a somewhat clumsy interface because it asks the caller to allocate the array. Rather than translating it, I think I would start here: How can I convert a hex string to a byte array?
Suppose I want to use an If statement, but I won't know until run-time what the actual condition of the If statement will be. Is there a way to do this by passing the condition as the contents of a string? As an example of the kind of thing I'm looking to acheive, consider the following bit of code;
Dim a as Integer = 1
Dim b as Integer = 2
Dim ConditionString As String = "<"
If a ConditionString b Then
...
End If
Mainly what I'm looking for is some way to leave the actual condition undefined until run-time. The reason I want to do this is because I need to have a set of threshold conditions in a database including not just the numeric values themselves, but also comparison operations. I might want to have something that amounts to "> 3.2 And < 5.6". As numbers are pulled in from data, the comparison operations need to be applied to the data depending on various conditions. Also, the database would be changed from time-to-time.
For such cases I love to use NCalc library, it has everything you need - it parses simple expressions (including logical and relational). Here is an example of it in C#:
var expr = new Expression("[X] > 3.2 and [X] < 5.6");
expr.Parameters["X"] = 10.0;
if (expr.Evaluate())
{
// ...
}
and VB.NET:
Dim expr As var = New Expression("[X] > 3.2 and [X] < 5.6")
expr.Parameters("X") = 10
If expr.Evaluate Then
' ...
End If
You can store a map of String to Func(Of Integer, Integer, Boolean) keyed by the strings "<", ">", "==", and so on, and take addresses of the functions that implement those conditions. For example:
Function LessThan(Integer a, Integer b) As Boolean
Return a < b
End Function
Dim Comparisons As New Map(Of String, Func(Of Integer, Integer, Boolean))
Comparisons.Add("<", AddressOf LessThan)
And then you can call it as such:
Dim a as Integer = 1
Dim b as Integer = 2
Dim ConditionString As String = "<"
If Comparisons(ConditionString)(a, b) Then
There are only a few possible conditions so I would just use a Select..Case statement:
Select Case ConditionString
Case "<"
Case ">"
'etc.
Case Else
End Select
Otherwise, you cannot (simply) convert a string "<" to an operator.
You just need a 'code', mapping some kind of value that you can store in a database to the various kinds of "conditions" you wish to test. Instead of a string, I'd suggest using an enum:
Enum ConditionEnum
LessThan
GreaterThan
Equal
SomeOtherVeryComplicatedBinaryFunction
End Enum
And then define a method that evaluates the condition along with the two arguments:
Public Sub EvaluateConditionWithArguments(ConditionEnum condition, Integer a, Integer b) As Boolean
EvaluateConditionWithArguments = False
Select Case condition
Case ConditionEnum.LessThan
If a < b Then
EvaluateConditionWithArguments = True
End If
...
End Select
End Sub
This is my first time on Stack Overflow and I am trying to understand what '=' means in the last line of this code:
Dim label As Label = Me.labels.Item(String.Concat(New Object() { movimiento.Sector1.ID, "-", movimiento.X1, "-", movimiento.Y1 }))
Dim dictionary As Dictionary(Of Label, Integer)
Dim label3 As Label
dictionary = Me.demandas2.Item(label3 = label) = (dictionary.Item(label3) - 1)
Any kind of help will be welcome, thanks in advance!
The equals sign (=) is used for two entirely different operators in VB.NET. It is used as the assignment operator as well as for the equality test operator. The operator, to which the character evaluates, depends on the context. So, for instance, in this example:
Dim x As Integer = 1
Dim y As Integer = 2
Dim z As Integer = x = y
You might think, as in other languages, such as C#, that after executing that code, x, y, and z would all equal 2. However, VB treats the second equals sign as an equality test operator. Therefore, in actuality, it's doing this:
If x = y Then
z = True
Else
z = False
End If
You'll notice, though, that we are then trying to assign a boolean value to an integer variable. If you have Option Strict On (as you should), it would not allow you to do that. If that's really what you wanted to do, it would force you to cast it to an integer, which makes it slightly more obvious:
z = CInt(x = y)
However, it's still confusing, so typically, this kind of thing is discouraged in VB.NET. So, I suspect that the code you posted wouldn't even compile if Option Strict was turned on. But, this is what it's actually trying to do:
Dim temp1 As Boolean = (label3 = label) ' Evaluates to False
Dim temp2 As Boolean = (Me.demandas2.Item(temp1) = (dictionary.Item(label3) - 1)) ' Likely evaluates to False
dictionary = temp2 ' Couldn't possibly be a valid assignment
Let's look at this line of code:
dictionary = Me.demandas2.Item(label3 = label) = (dictionary.Item(label3) - 1)
The first = is an assignment. So we assign the right part to the dictionary. Now for the right part:
Me.demandas2.Item(label3 = label) = (dictionary.Item(label3) - 1)
The = between the two expressions is a comparison, so it returns a Boolean. So the supposed "dictionary" is assigned a boolean value. If we check the left part of that expression:
Me.demandas2.Item(label3 = label)
Once again, the = sign here is doing a comparison, so if label3 is the same as label, then the code would be equivalent to Me.semandas2.Item(True). This seems strange.
Overall, this code doesn't make much sense, and I'd be surprised if it compiled, considering it tries to assign a boolean to a dictionary. It certainly wouldn't compile with Option Strict On.
Thanks a lot, everyone. The snippet was result of decompile a dll. I was trying to help a partner.
.Net reflector decompiled based on VB.Net code, that was a mistake.
Finally we see that first it should decompile using C# code, that gives a complete different meaning to the code:
if (movimiento.Contenedor.Demanda2)
{
Dictionary<Label, int> dictionary;
Label label3;
(dictionary = this.demandas2)[label3 = label] = dictionary[label3] - 1;
if (this.demandas2[label] == 0)
{
label.ForeColor = Color.Black;
}
(dictionary = this.demandas2)[label3 = label2] = dictionary[label3] + 1;
label2.ForeColor = Color.DarkOrange;
}
In VBA and VB6 I can assign something to mid for Example mid(str,1,1)="A" in VBS this doesn't work.
I need this because String concatenation is freakin' slow
Here is the actual code i hacked together real quick
Function fastXMLencode(str)
Dim strlen
strlen = Len(str)
Dim buf
Dim varptr
Dim i
Dim j
Dim charlen
varptr = 1
buf = Space(strlen * 7)
Dim char
For i = 1 To strlen
char = CStr(Asc(Mid(str, i, 1)))
charlen = Len(char)
Mid(buf, varptr, 2) = "&#"
varptr = varptr + 2
Mid(buf, varptr, charlen) = char
varptr = varptr + charlen
Mid(buf, varptr, 1) = ";"
varptr = varptr + 1
Next
fastXMLencode = Trim(buf)
End Function
How can i get this to work in VBS?
Authoritative source explicitly stating it's not available in VBScript:
Visual Basic for Applications Features Not In VBScript:
Strings: Fixed-length strings LSet, RSet Mid Statement StrConv
VBA has both a Mid Statement and a Mid Function. VBScript only has the Mid Function.
The one other option you have if you are stuck doing this in VBScript is to make API calls. Since you are already comfortable working directly with the string buffer this might not be too big a jump for you. This page should get you started: String Functions
Sorry, it looks like API calls are out, too: Rube Goldberg Memorial Scripting Page: Direct API Calls Unless you want to write an ActiveX wrapper for your calls, but we're starting to get into an awful lot of work (and additional maintenance requirements) now.
You can't do that. You will have to rebuild the string from scratch.
This is not possible, mid(str,1,1) is a function which just returns a number (str is not passed 'by reference' and is not altered).
It's never too late to suggest an answer, even to a decade-old question...
One great thing about VBScript is that even though it's a subset of VB/VBA it still lets you declare (and use) classes. And having classes implies them having properties, with getters and/or setters... if you can guess where I'm going...
So if you wrap a class around a VBA-compatible implementation of Mid(), it's actually possible to emulate Mid() statements with a Let property. Consider the following code:
Class CVBACompat
' VB6/VBA-Like Mid() Statement
Public Property Let LetMid(ByRef Expression, ByVal StartPos, ByVal Length, ByRef NewValue) ' ( As String, As Long, As Long, As String)
Dim sInsert ' As String
sInsert = Mid(NewValue, 1, Length)
Expression = Mid(Expression, 1, StartPos - 1) & sInsert & Mid(Expression, StartPos + Len(sInsert))
End Property
' VB6/VBA-Like IIf() Function
Public Function IIf(Expression, TruePart, FalsePart)
If CBool(Expression) Then
IIf = TruePart
Else
IIf = FalsePart
End If
End Function
End Class: Public VBACompat: Set VBACompat = New CVBACompat: Public Function IIf(X, Y, Z): IIf = VBACompat.IIf(X, Y, Z): End Function
VBA's language specification says that when Mid( <string-expression>, <start> [, <length> ] ) is used as a statement, what's to be replaced in the source string <string-expression> is the lowest number of characters given the entire RHS expression or as limited by the <lenght> argument, when provided. Now, you can't have optional arguments in VBScript, so if you want to be able to also use statements of the sort Mid( <string-expression>, <start> ) = <expression> you'll have to have two separate implementations.
The implementation proposed above can be checked with the following code (not including checks for error-throwing conditions, which are the same as for the Mid() function anyway) :
Dim f ' As String
Dim g ' As String
f = "1234567890"
g = f
' VB6 / VBA: Mid(f, 5, 2) = "abc"
VBACompat.LetMid(f, 5, 2) = "abc"
' VB6 / VBA: Mid(g, 5, 4) = "abc"
VBACompat.LetMid(g, 5, 4) = "abc"
WScript.Echo "First call " & IIf(f = "1234ab7890", "passes", "fails")
WScript.Echo "Second call " & IIf(g = "1234abc890", "passes", "fails")
In any case, since the proposed solution is just an emulation of otherwise native code implementations (in VB6, VBA), and still implies string concatenation anyway with the overhead of class instantiation + VTable translations, the OP'd be better off creating and making available an ActiveX component (OCX) to do concatenations in series.