Unnamed Default Property - vbscript

In VBScript, some built in objects use an unnamed property. Some Examples:
Set Dict = Server.CreateObject("Scripting.Dictionary")
Set RS = GetEmloyeesRecordSet()
Dict("Beer") = "Tasty" ' Same as Dict.Item("Beer") = "Tasty"
Dict("Crude Oil") = "Gross" ' Same as Dict.Item("Crude Oil") = "Gross"
Response.Write "The First Employee Is: " & RS("Name") ' Same as RS.Fields("Name")
How can I use this same syntax in my own classes?
UPDATE
Here is a working, stand-alone example of how to do this, a simple wrapper for Scripting.Dictionary. Note the use of "Let" to allow the d("key") = "value" syntax. Of course credit goes to Thom for providing the answer.
<%
Class DictWrapper
Private Dict
Private Sub Class_Initialize()
Set Dict = Server.CreateObject("Scripting.Dictionary")
End Sub
Private Sub Class_Terminate()
Set Dict = Nothing
End Sub
Public Property Get Count
Count = Dict.Count
End Property
Public Default Property Get Item( Key )
Item = Dict(Key)
End Property
Public Property Let Item( Key, Value )
Dict(Key) = Value
End Property
Public Sub Add( Key, Value )
Dict.Add Key, Value
End Sub
End Class
Dim d : Set d = New DictWrapper
d.Add "Beer", "Good"
Response.Write d("Beer") & "<br>"
d("Beer") = "Bad"
Response.Write d("Beer")
%>

You need to declare a property of the class as the default property. As an example, here's part of a String wrapper class I wrote:
class StringClass
private finished_
private data_
private size_
public function init (val)
finished_ = cStr(val)
set init = me
end function
public default property get value
if (size_ > 0) then
finished_ = finished_ & join(data_, vbNullString)
data_ = empty
size_ = 0
end if
value = finished_
end property
public property let value (val)
data_ = empty
size_ = empty
init(val)
end property
public function add (s)
size_ = size_ + 1
if (isEmpty(data_)) then
redim data_(MIN_ARRAY_SIZE)
elseif (size_ > uBound(data_)) then
redim preserve data_(Float(uBound(data_) * GRANTED_HEAD_ROOM).ceil)
end if
data_(size_ - 1) = cStr(s)
end function
end class
Usage:
dim s: set s = new StringClass
s()= "Hello, world!" ' s.value() = "Hello, world!"
Response.Write s ' Response.Write s.value()
You can also have a parametrized default property:
class ListClass
private size_
private data_
private sub CLASS_INITIALIZE
size_ = 0
data_ = Array()
resize_array MIN_ARRAY_SIZE
end sub
public default property get data (index)
if isObject(data) then
set data_(index) = data
else
data_(index) = data
end if
end property
public property let data (index, value)
data_(index) = value
end property
public property set data (index, value)
set data_(index) = value
end property
public function add(datum)
size_ = size_ + 1
if (size_ > uBound(data_) + 1) then expand_array
assign data_(size_ - 1), datum
add = datum
end function
end class
dim l: set l = new ListClass
l.add("Hello, world!")
l(0) = "Goodbye, world!"
Response.Write l(0)
This second example is probably what you were looking for, using default properties to implement collections, but it's worth checking out the first example, using default properties to implement auto-unboxing of wrapper classes.

Related

Can I use System.Collections.Generic.SortedList in VBscript?

I'm trying to generate a sorted list in VBscript doing this:
Set GNDcons = CreateObject( "System.Collections.Generic.SortedList<string, integer>" )
however it doesn't work, I get Scode:800a01ad
Is it even possible to use this type in VBscript? I saw there's another SortedList in System.Collections without the possibility of setting the data types but the use was deprecated.
You can use the System.Collections.SortedList type in VBScript; just avoid the System.Collections.Generic types, and constructors requiring parameters.
Here's a simple example:
Dim sl : Set sl = CreateObject("System.Collections.SortedList")
sl.Capacity = 5
sl.Add "Just", 0
sl.Add "One", 1
sl.Add "Of", 2
sl.Add "Many", 3
sl.Add "Examples", 4
Dim i, k, v
For i = 0 To sl.Count-1
k = sl.GetKey(i)
v = sl.Item(k)
WScript.Echo "Item at index " & i & " contains key " & k & " and value " & v
Next
If you want to simulate type constraints for keys and values, then you can create a VBScript wrapper class. For example:
Option Explicit
Class CSortedList
Private sl
Private TKeyVarType
Private TValueVarType
Private Sub Class_Initialize()
TKeyVarType = vbEmpty
TValueVarType = vbEmpty
Set sl = CreateObject("System.Collections.SortedList")
End Sub
Private Sub Class_Terminate()
Set sl = Nothing
End Sub
Public Property Let TKey(ByVal VarType_)
TKeyVarType = VarType_
End Property
Public Property Get TKey()
TKey = TKeyVarType
End Property
Public Property Let TValue(ByVal VarType_)
TValueVarType = VarType_
End Property
Public Property Get TValue()
TValue = TValueVarType
End Property
Public Property Let Capacity(ByVal v_)
sl.Capacity = v_
End Property
Public Property Get Capacity()
Capacity = sl.Capacity
End Property
Public Property Get Count()
Count = sl.Count
End Property
Public Property Get IsFixedSize()
IsFixedSize = sl.IsFixedSize
End Property
Public Property Get IsReadOnly()
IsReadOnly = sl.IsReadOnly
End Property
Public Property Get IsSynchronized()
IsSynchronized = sl.IsSynchronized
End Property
Public Property Let Item(ByVal key, ByVal value)
If VarType(key) <> TKeyVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for key"
ElseIf VarType(value) <> TValueVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for value"
Else
sl.Item(key) = value
End If
End Property
Public Property Get Item(ByVal key)
If VarType(key) <> TKeyVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for key"
ElseIf vbObject = VarType(sl.Item(key)) Then
Set Item = sl.Item(key)
Else
Item = sl.Item(key)
End If
End Property
Public Property Get Keys()
Set Keys = sl.Keys
End Property
Public Property Get SyncRoot()
Set SyncRoot = sl.SyncRoot
End Property
Public Property Get Values()
Set Values = sl.Values
End Property
Public Sub Add(ByVal key, ByVal value)
If VarType(key) <> TKeyVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for key"
ElseIf VarType(value) <> TValueVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for value"
Else
sl.Add key, value
End If
End Sub
Public Sub Clear()
sl.Clear
End Sub
Public Function Clone()
Set Clone = sl.Clone()
End Function
Public Function Contains(ByVal key)
If VarType(key) <> TKeyVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for key"
Else
Contains = sl.Contains(key)
End If
End Function
Public Function ContainsKey(ByVal key)
ContainsKey = Contains(key)
End Function
Public Function ContainsValue(ByVal value)
If VarType(value) <> TValueVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for value"
Else
ContainsValue = sl.ContainsValue(value)
End If
End Function
Public Function GetByIndex(ByVal index)
If vbObject = VarType(sl.GetByIndex(index)) Then
Set GetByIndex = sl.GetByIndex(index)
Else
GetByIndex = sl.GetByIndex(index)
End If
End Function
Public Function GetEnumerator()
Set GetEnumerator = sl.GetEnumerator()
End Function
Public Function GetKey(ByVal index)
If vbObject = sl.GetKey(index) Then
Set GetKey = sl.GetKey(index)
Else
GetKey = sl.GetKey(index)
End If
End Function
Public Function GetKeyList()
Set GetKeyList = sl.GetKeyList()
End Function
Public Function GetValueList()
Set GetValueList = sl.GetValueList()
End Function
Public Function IndexOfKey(ByVal key)
If VarType(key) <> TKeyVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for key"
Else
IndexOfKey = sl.IndexOfKey(key)
End If
End Function
Public Function IndexOfValue(ByVal value)
If VarType(value) <> TValueVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for value"
Else
IndexOfValue = sl.IndexOfValue(value)
End If
End Function
Public Sub Remove(ByVal key)
If VarType(key) <> TKeyVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for key"
Else
sl.Remove key
End If
End Sub
Public Sub RemoveAt(ByVal index)
sl.RemoveAt index
End Sub
Public Sub SetByIndex(ByVal index, ByVal value)
If VarType(value) <> TValueVarType Then
WScript.StdErr.WriteLine "Error: Wrong type for value"
Else
sl.SetByIndex index, value
End If
End Sub
Public Sub TrimToSize()
sl.TrimToSize
End Sub
End Class
With New CSortedList
.TKey = vbString
.TValue = vbInteger
.Capacity = 5
.Add "Just", 0
.Add "One", 1
.Add "Of", 2
.Add "Many", 3
.Add "Examples", 4
Dim i, k, v
For i = 0 To .Count-1
k = .GetKey(i)
v = .Item(k)
WScript.Echo "Item at index " & i & " contains key " & k & " and value " & v
Next
End With
Note: The above wrapper class has not been 100% tested, but does restrict keys to Variant string subtypes, and values to Variant integer subtypes. The resulting list is automatically sorted by keys.
Output:
Item at index 0 contains key Examples and value 4
Item at index 1 contains key Just and value 0
Item at index 2 contains key Many and value 3
Item at index 3 contains key Of and value 2
Item at index 4 contains key One and value 1

Classic ASP: How to sort a dictionary If It has class Items for values

I need to sort a dictionary by its key, but the values are class items.
Here is the class:
CLASS Person
PUBLIC PersonID
PUBLIC PersonName
PUBLIC GenderID
PUBLIC PersonAdditional
PRIVATE SUB class_initialize()
PersonID = null
PersonName = null
GenderID = null
PersonAdditional = null
END SUB
END CLASS
And here is my dictionary, filled with data from an array:
Set dict = Server.CreateObject("Scripting.Dictionary")
FOR i = 0 TO UBOUND(arr_People)
key_person = arr_People(i).GenderID & arr_People(i).PersonName
dict.Add key_person, new Person
dict.Item(key_person).PersonName = arr_People(i).PersonName
dict.Item(key_person).GenderID = arr_People(i).GenderID
dict.Item(key_person).PersonID = arr_People(i).PersonID
dict.Item(key_person).PersonAdditional = arr_People(i).PersonAdditional
NEXT
I use this function for sorting, but it doesn't seem to work:
Function SortDictionary(objDict,intSort)
Dim strDict()
Dim objKey
Dim strKey,strItem
Dim X,Y,Z
Z = objDict.Count
If Z > 1 Then
ReDim strDict(Z,2)
X = 0
For Each objKey In objDict
strDict(X,dictKey) = CStr(objKey)
strDict(X,dictItem) = CStr(objDict(objKey))
X = X + 1
Next
For X = 0 to (Z - 2)
For Y = X to (Z - 1)
If StrComp(strDict(X,intSort),strDict(Y,intSort),vbTextCompare) > 0 Then
strKey = strDict(X,dictKey)
strItem = strDict(X,dictItem)
strDict(X,dictKey) = strDict(Y,dictKey)
strDict(X,dictItem) = strDict(Y,dictItem)
strDict(Y,dictKey) = strKey
strDict(Y,dictItem) = strItem
End If
Next
Next
objDict.RemoveAll
For X = 0 to (Z - 1)
objDict.Add strDict(X,dictKey), strDict(X,dictItem)
Next
End If
End Function
It gives me the following error:
Object doesn't support this property or method
on this row:
strDict(X,dictItem) = CStr(objDict(objKey)
I'm assuming that this happens because the values in the dictionary contains class instead of just a string or integer, but I don't know how to handle it.
There's a workaround that you can use:
Create another array containing only the keys of the dictonary
Sort the array
Read the dictionary values by iterating trough the array of keys
And here's the code:
Set dict = Server.CreateObject("Scripting.Dictionary")
Set arr_personKeys = CreateObject("System.Collections.ArrayList")
FOR i = 0 TO UBOUND(arr_People)
key_person = arr_People(i).GenderID & arr_People(i).PersonName
arr_personKeys.Add key_person
dict.Add key_person, new Person
dict.Item(key_person).PersonName = arr_People(i).PersonName
dict.Item(key_person).GenderID = arr_People(i).GenderID
dict.Item(key_person).PersonID = arr_People(i).PersonID
dict.Item(key_person).PersonAdditional = arr_People(i).PersonAdditional
NEXT
arrLength_personKeys = arr_personKeys.count - 2
SortArray arr_personKeys,arrLength_personKeys
And here is the sorting function:
Function SortArray(arrayForSorting, arraySize)
for a = arraySize To 0 Step -1
for j = 0 to a
if arrayForSorting(j)>arrayForSorting(j+1) then
temp=arrayForSorting(j+1)
arrayForSorting(j+1)=arrayForSorting(j)
arrayForSorting(j)=temp
end if
next
next
End Function
Now you can iterate trough your sorted dictionary like this:
For i = 0 To arrLength_personKeys + 1
key = arr_personKeys(i)
Response.write dict(key).PersonID
Response.write dict(key).PersonName
Response.write dict(key).GenderID
Response.write dict(key).PersonAdditional
Next

Wrong number of arguments or invalid property assignment using classes

Could anyone explain why I get this error on line 12? It is clearly an array. Why can I not obtain the value in index position 0 in this way? Do I really need that extra variable (arr)?
Option Explicit
Dim obj
Set obj = new ClsTest
obj.singleval = "test"
MsgBox obj.singleval ' test
obj.repeatingval = split ("a,b,c", ",")
MsgBox IsArray(obj.repeatingval) ' true
MsgBox UBound(obj.repeatingval) ' 2
MsgBox obj.repeatingval(0) ' Wrong number of arguments or invalid
' property assignment: 'repeatingval'
Dim arr : arr = obj.repeatingval
MsgBox IsArray(arr) ' true
MsgBox UBound(arr) ' 2
MsgBox arr(0) ' a
Class ClsTest
Private m_singleval
Private m_repeatingval
Public Property Get singleval()
singleval = m_singleval
End Property
Public Property Let singleval(w)
m_singleval = w
End Property
Public Property Get repeatingval()
repeatingval = m_repeatingval
End Property
Public Property Let repeatingval(w)
m_repeatingval = w
End Property
End Class
If you want indexed access to the (array) property repeatingval you need to change the property definition to include an index. Beware, though, that getter and setter must be defined alike:
Class ClsTest
...
Public Property Get repeatingval(i)
repeatingval = m_repeatingval(i)
End Property
Public Property Let repeatingval(i, w)
m_repeatingval(i) = w
End Property
End Class
You can't have a property where the setter takes an array and the getter returns an element of that array. To be able to assign an array and retrieve an element of that array, you need 2 different properties:
Class ClsTest
...
Public Property Get repeatingval(i)
repeatingval = m_repeatingval(i)
End Property
Public Property Let repeatingval(i, w)
m_repeatingval(i) = w
End Property
Public Property Get repeatingarr
repeatingval = m_repeatingval
End Property
Public Property Let repeatingarr(w)
m_repeatingval = w
End Property
End Class
Set obj = New ClsTest
obj.repeatingarr = Split("a,b,c", ",")
MsgBox IsArray(obj.repeatingarr)
MsgBox UBound(obj.repeatingarr)
MsgBox obj.repeatingval(0)
Do I really need that extra variable (arr)?
You can do MsgBox obj.repeatingval()(0)
Dim thing
For Each thing in obj.repeatingval
msgbox thing
Next
This will give you access to it.

Sorting the TimeZoneCollection list

Issue definition
I use the OpenNetCF TimeZoneCollection class to display in a ComboBox all the available time zones.
Dim tzc As New TimeZoneCollection
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
For Each tzi As TimeZoneInformation In tzc
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
But they are not sorted:
How could I sort the list?
Alphabetical order is fine, time shift order is better.
Replicate this issue on your side (need VS and a CE device)
Create an empty Smart Device project (Visual Basic)
Download OpenNetCF Community Edition (free)
Add OpenNETCF.WindowsCE.dll as Reference (right click on the project -> Add Reference)
Open Form1, add a combobox, and paste code below:
Imports OpenNETCF.WindowsCE
Public Class Form1
Private Sub Form1_Activated(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Activated
Dim tzc As New TimeZoneCollection
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
For Each tzi As TimeZoneInformation In tzc
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
End Sub
End Class
I realize my problem was a bit easy to solve. So, I found a simple way, in using the built-in Sort() method of the ArrayList.
what I do:
copy the DisplayName in an ArrayList of String
Sort it
Use it to re-index the collection of TimeZoneInformation.
My code:
Dim tzc As New TimeZoneCollection ' the raw collection'
Dim ar_s As New ArrayList() ' the array used to sort alphabetically the DisplayName'
Dim tzc_s As New TimeZoneCollection ' the sorted collection'
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
' copy the display name in an array to sort them'
For Each tzi As TimeZoneInformation In tzc
ar_s.Add(tzi.DisplayName)
Next
ar_s.Sort()
' populated tzc_s, a sorted collection of TimeZoneInformation'
For i As Integer = 0 To ar_s.Count - 1
For Each tzi As TimeZoneInformation In tzc
If ar_s(i) = tzi.DisplayName Then
tzc_s.Add(tzi)
Continue For
End If
Next
Next
' Bind the sorted ArrayList to the ComboBox'
For Each tzi As TimeZoneInformation In tzc_s
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
I would subclass the TimeZoneCollection and add a Sort method as you alreday found but more or less implement by hand. I was not bale to verify the following as I do not have a compact framework here:
In the subclassed TimeZoneCollection add a sort method and a IComparable class. Within that class you can define whatever sort order you wich (by names, by GMT-offset...):
...
public class myTimeZoneCollection:TimeZoneCollection{
...
public class myTZIComparer : IComparer {
// return -1 for a is before b
// return +1 for a is after b
// return 0 if a is same order as b
int IComparer.Compare( Object a, Object b ) {
{
TZData c1=(TZData)a;
TZData c2=(TZData)b;
if (c1.GMTOffset > c2.GMTOffset)
return -1;//1; //this will result in reverse offset order
if (c1.GMTOffset < c2.GMTOffset)
return 1;//-1;
else
return 0;
}
}
...
public void sort(){
// Sorts the values of the ArrayList using the reverse case-insensitive comparer.
IComparer myComparer = new myTZIComparer();
this.Sort( myComparer );
}
...
}
And yes, I am sorry, this is in C# but must be do also in VB.
And, use the sorted my TimeZoneCollection to add the elements to the combobox. There is no additional work needed to get the list into the combobox in a custom sort order. Just do foreach and add.
Here is the promised full VB solution with the OpenNetCF fix:
myTimeZoneCollection.vb:
Option Strict On
Option Explicit On
Imports OpenNETCF.WindowsCE
Public Class myTimeZoneCollection
Inherits TimeZoneCollection
Dim tzc As New TimeZoneCollection
Public Sub New()
End Sub
Overloads Function Initialize() As TimeZoneCollection
tzc.Initialize()
Dim myComparer = New myTZIComparer()
tzc.Sort(myComparer)
Return tzc
End Function
Shared Function getOffsetFromDisplayName(ByVal tzi As TimeZoneInformation) As Integer
' known forms
' GMT = no offset
' GMT+6 = 6 hours offset
' GMT-12 = -6 hours offset
' GMT+4:30 = 4 hours and 30 minutes offset
' GMT-4:30 = - 4 hours and 30 minutes offset
' all these end with a space! followed by the name of the time zone
'System.Diagnostics.Debug.WriteLine("getOffsetFromDisplayName: tzi=" & tzi.ToString())
'extract offset
If (tzi.DisplayName = "GMT") Then
Return 0
End If
Dim subStr As String
subStr = tzi.DisplayName.Substring(0, tzi.DisplayName.IndexOf(" "c)) 'GMT+x or GMT-x or GMT+x:yy or GMT-x:yy
If (subStr = "GMT") Then
Return 0
End If
subStr = subStr.Substring(3) 'cut GMT from begin
'now check if this is with a minute value
Dim hoursOffset, minutesOffset, idxOfColon, idxM As Integer : idxOfColon = 0 : idxM = 0
idxOfColon = subStr.IndexOf(":"c)
If (idxOfColon = -1) Then 'no : found
hoursOffset = System.Int32.Parse(subStr)
minutesOffset = hoursOffset * 60
Else
Dim sH, sM As String
sH = subStr.Substring(0, subStr.Length - idxOfColon - 1)
sM = subStr.Substring(idxOfColon + 1)
hoursOffset = System.Int32.Parse(sH)
minutesOffset = System.Int32.Parse(sM)
If (hoursOffset > 0) Then
minutesOffset = minutesOffset + hoursOffset * 60
Else
minutesOffset = hoursOffset * 60 - minutesOffset
End If
End If
Return minutesOffset
End Function
Class myTZIComparer
Implements IComparer
'// return -1 for a is before b
'// return +1 for a is after b
'// return 0 if a is same order as b
Public Function Compare(ByVal a As Object, ByVal b As Object) As Integer Implements IComparer.Compare
Dim c1 As TimeZoneInformation = CType(a, TimeZoneInformation)
Dim c2 As TimeZoneInformation = CType(b, TimeZoneInformation)
Dim offset1, offset2 As Integer
offset1 = getOffsetFromDisplayName(c1)
offset2 = getOffsetFromDisplayName(c2)
If (offset1 > offset2) Then
Return -1 '//1; //this will result in reverse offset order
ElseIf (offset1 < offset2) Then
Return 1 '//-1;
Else 'offsets equal, sort by name
If (c1.DisplayName < c2.DisplayName) Then
Return -1
ElseIf (c1.DisplayName > c2.DisplayName) Then
Return 1
Else
Return 0
End If
End If
End Function
End Class
End Class
By changing or adding another myTZIComparer you can define the order of the entries.
The OpenNetCF code is wrong for the new timezone names
' GMT+4:30 = 4 hours and 30 minutes offset
' GMT-4:30 = - 4 hours and 30 minutes offset
as it does only look for full hour offsets. So I needed to develop a new 'parser' to get the bias data.
In your code with the listbox:
Public Sub fillList()
ComboBox1.Items.Clear()
Dim tzc As New TimeZoneCollection
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
For Each tzi As TimeZoneInformation In tzc
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
End Sub
The above fills the list in the order the items are.
Public Sub fillListGMT()
ComboBox1.Items.Clear()
Dim tzc As New myTimeZoneCollection 'subclassed one
Dim TheIndex As Integer
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
Dim tzc1 As New TimeZoneCollection
tzc1.Clear()
tzc1 = tzc.Initialize()
For Each tzi As TimeZoneInformation In tzc1
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
End Sub
The code above fills the list ordered by GMT offset.
This answer is based on #Josef's idea (written in C#), and translated to VB.
This is the customized class:
Public Class myTimeZoneCollection
Inherits TimeZoneCollection
Public Class myTZIComparer
Implements IComparer
' return -1 for a is before b
' return +1 for a is after b
' return 0 if a is same order as b '
Public Function Compare(ByVal a As Object, ByVal b As Object) As Integer _
Implements IComparer.Compare
Dim c1 As TimeZoneInformation = CType(a, TimeZoneInformation)
Dim c2 As TimeZoneInformation = CType(b, TimeZoneInformation)
If (c1.Bias > c2.Bias) Then
Return -1 ' 1; //this will result in reverse offset order'
End If
If (c1.Bias < c2.Bias) Then
Return 1 ' -1;'
Else ' sort by name '
If (c1.DisplayName < c2.DisplayName) Then
Return -1
End If
If (c1.DisplayName > c2.DisplayName) Then
Return 1
Else
Return 0
End If
End If
End Function
End Class
Public Sub MySort()
' Sorts the values of the ArrayList using the specific sort Comparer (by Bias)'
Dim myComparer As IComparer = New myTZIComparer()
Me.Sort(myComparer)
End Sub
End Class
And this is the usage in the form
Private Sub Form1_Activated(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Activated
Dim tzc As New myTimeZoneCollection ' this is the customized class
Dim TheIndex As Integer ' this index is used to select the activated time zone of the system
Dim MyTimeZoneInfo As New TimeZoneInformation
DateTimeHelper.GetTimeZoneInformation(MyTimeZoneInfo)
tzc.Initialize()
tzc.MySort()
' Clear the item list otherwise it is increased at each Activated event.. '
ComboBox1.Items.Clear()
For Each tzi As TimeZoneInformation In tzc
TheIndex = ComboBox1.Items.Add(tzi)
If tzi.StandardName = MyTimeZoneInfo.StandardName Then
ComboBox1.SelectedIndex = TheIndex
End If
Next
End Sub
I validated this code on a device, it works fine.

Overload constructors in VBScript

I found a way to extend classes in VBScript, but are there any ways to pass in parameters or overload the constructor? I am currently using an Init function to initialize the properties, but would like to be able to do this when I create the object.
This is my sample class:
Class Test
Private strText
Public Property Get Text
Text = strText
End Property
Public Property Let Text(strIn)
strText = strIn
End Property
Private Sub Class_Initialize()
Init
End Sub
Private Sub Class_Terminate()
End Sub
Private Function Init
strText = "Start Text"
End Function
End Class
And I create it
Set objTest = New Test
But would like to do something like this
Set objTest = New Test(strInitText)
Is this possible, or does the object have to be created and initialized in two setps?
Just to alter slightly on svinto's method...
Class Test
Private m_s
Public Default Function Init(s)
m_s = s
Set Init = Me
End Function
Public Function Hello()
Hello = m_s
End Function
End Class
Dim o : Set o = (New Test)("hello world")
Is how I do it. Sadly no overloading though.
[edit]
Though if you really wanted to you could do something like this...
Class Test
Private m_s
Private m_i
Public Default Function Init(parameters)
Select Case UBound(parameters)
Case 0
Set Init = InitOneParam(parameters(0))
Case 1
Set Init = InitTwoParam(parameters(0), parameters(1))
Else Case
Set Init = Me
End Select
End Function
Private Function InitOneParam(parameter1)
If TypeName(parameter1) = "String" Then
m_s = parameter1
Else
m_i = parameter1
End If
Set InitOneParam = Me
End Function
Private Function InitTwoParam(parameter1, parameter2)
m_s = parameter1
m_i = parameter2
Set InitTwoParam = Me
End Function
End Class
Which gives the constructors...
Test()
Test(string)
Test(integer)
Test(string, integer)
which you can call as:
Dim o : Set o = (New Test)(Array())
Dim o : Set o = (New Test)(Array("Hello World"))
Dim o : Set o = (New Test)(Array(1024))
Dim o : Set o = (New Test)(Array("Hello World", 1024))
Bit of a pain though.
You can work around it by having your Init function returning the object itself...
Class Test
Private m_s
Public Function Init(s)
m_s = s
Set Init = Me
End Function
Public Function Hello()
Hello = m_s
End Function
End Class
Dim o
Set o = (New Test).Init("hello world")
Echo o.Hello
You have to do it in two steps. VB Script doesn't support overloading so you can't modify the default constructor with new parameters. Same goes for Vb6
A bit hackish, for sure, but when I need varargs in calls, one of my parameters I pass in as an array, i.e.
Rem printf done poorly
sub printf(fmt, args)
dim fp, vap:
dim outs:
dim fini:
fini = 0:
vap = 0:
while (not fini)
fp = index(fmt,"%"):
if (not(isNull(fp))) then
' do something with %f, %s
select case(fp)
case 'c':
outs = outs & charparse(args(vap)):
case 's':
outs = outs & args(vap):
' and so on. Quite incomplete but you get the idea.
end select
vap = vap + 1
end if
wend
end sub
printf("%s %d\n",array("Hello World", 42)):

Resources