I have this simple Address class, that only have:
Public street as String
Public number as Integer
Then, i'm creating a instance inside a module calle "mdl1", and using it on the same module function:
Public objectAddress as Address
Public Function f1() As String
Set objectAddress = New Address
objectAddress = "5th street" 'this works fine
If Not isNothing() Then
f1 = objectAddress.street
Else
f1 = vbNullString
End If
End Function
Public Function isNothing() As Boolean
'When entering here, the objectAddres is ALWAYS Nothing, even though i just assigned a value to the street property...
If objectAddress is Nothing then
isNothing = True
Else
isNothing = False
End If
End Function
I've assigned a value to objectAdrress.street on the f1() function, but when it enters the ìsNothing()`function, the objectAddress is Nothing again.
And when the control comes back to the f1 function, the object returns to having a value and the street property still have the value i assigned it...
So, shouldn't a module "property" behave like a class one? Or the global/local scope doesn't exist inside a module?
SOLVED:
Even though no one got the point of the question, the problem was that I was creating a local object with the same name of the global one, that's why it was always Nothingwhen it entered another function.
Related
I'm refactoring an ASP.NET MVC application that contains a Grid that uses remote filtering, sorting and pagination, it currently uses a string to pass the comparison operator that should be applied, I'd like to change that into an Enum:
Public Class MyController
Inherits Controller
Public Function GetOrders(filterModels As List(Of FilterModel)) As JsonResult
'A member of FilterModel is of type EnumComparisonOperators here
...
End Function
End Class
Public Enum EnumComparisonOperators
<Description("=")>
Equals = 0
<Description("<>")>
NotEquals = 1
<Description("<=")>
LessThanOrEquals = 2
<Description(">")>
GreaterThan = 3
<Description(">=")>
GreaterThanOrEquals = 4
End Enum
In the View:
//In the real code, my ajax call is in a callback from a third party
//component that just passes these loadOptions
var loadOptions = {
filterModel: {
operator: "=" //Replacing this string with "Equals" causes the code to work
//But my application logic needs a "=" sign, so I'd like to avoid
//converting back and forth
}
};
//The exception gets thrown the server when it receives this post call
$.post("/My/GetOrders", loadOptions);
My problem is that this results in an exception (= is not a valid value for EnumComparisonOperators.) as the calling grid component uses the string "=" for the "equals" operation and the controller doesn't parse that automatically, so my question is:
Is there a way for me to change/decorate/configure the Enum, so that "=" is recognized by the controller as a valid value as opposed to "Equals".
So in essence I'm trying to achieve the behavior I would get if = were the name of my enum's value, but = is a special character so I used Equals and am looking for configuration that would make it behave like =, that means, parsing and serialization should use =
The exception "= is not a valid value for EnumComparisonOperators" indicates that you're passing string which doesn't recognized as proper enum value (which contains integer indexes). You can keep <Description> attributes for each enum members (because you can't use operator symbols as enum member like EnumComparisonOperators.= or EnumComparisonOperators.<=), but it's necessary to write your own function to set enum member value from operator key in JSON using reflection like example below (adapted from this reference):
Public Function GetDescription(Of T)(ByVal value As T) As String
Dim field As FieldInfo = value.[GetType]().GetField(value.ToString())
Dim attributes As DescriptionAttribute() = CType(field.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
If attributes IsNot Nothing AndAlso attributes.Length > 0 Then
Return attributes(0).Description
Else
Return value.ToString()
End If
End Function
Public Function GetEnumValueFromOperator(Of T)(ByVal op As String) As T
Dim array As Array = [Enum].GetValues(GetType(T))
Dim list = New List(Of T)(array.Length)
For i As Integer = 0 To array.Length - 1
list.Add(CType(array.GetValue(i), T))
Next
Dim dic = list.[Select](Function(x) New With {
.Value = v,
.Description = GetDescription(x)
}).ToDictionary(Function(s) s.Description, Function(s) s.Value)
Return dic(op)
End Function
Afterwards, call the function above inside controller action (depending on your current implementation, these codes are subject to change):
Model
Public Class FilterModel
Public Property operator As String
' other properties
End Class
Controller
<HttpPost()>
Public Function GetOrders(filterModels As List(Of FilterModel)) As JsonResult
' check against null or zero length (filterModels.Count = 0) first
For Each fm As FilterModel In filterModels
Dim selectedOperator = GetEnumValueFromOperator(Of EnumComparisonOperators)(fm.operator)
Select Case selectedOperator
Case 0 ' Equals
' do something
End Select
Next
' other stuff
Return Json(...)
End Function
See also this fiddle for another usage example.
Note: Another available alternative is using EnumMemberAttribute like <EnumMember(Value := "=")> for every enum members and create a function to read that value as described in this issue.
I have an issue with assigning/retrieving correct values to/from an array which is within a class in VBScript. Whenever I try to set the array's value through a stand-alone function, it just does not work and I keep getting the old array values.
Here is an example code:
Class NewClass
Public TestValues
Public Sub Init()
TestValues = array("value0", "value1", "value2")
End Sub
End Class
Class NewFunctions
Public Function GetValue(xRef)
GetValue = xRef(2)
print "Value within Function: " & xRef(2)
End Function
Public Sub SetValue(xRef, xValue)
xRef(2) = xValue
print "Value within Sub: " & xRef(2)
End Sub
End Class
Dim MyClass, MyFunction
Set MyClass = New NewClass
Set MyFunction = New NewFunctions
Now, when I try to set the index 2 of the given array MyClass.TestValues with the SetValue Sub, it claims the new value has been set, but when I then call GetValue for this array or print out the content of the MyClass.TestValues(2) directly, I am still getting the old values:
MyFunction.SetValue MyClass.TestValues, "newvalue2"
It returns: Value within Sub: newvalue2
But when I retrieve the value with GetValue:
MyFunction.GetValue MyClass.TestValues
It returns: Value within Function: value2, which is the old value.
When I, however, set the array directly:
Myclass.TestValues(2) = "newvalue2"
then calling with:
MyFunction.GetValue MyClass.TestValues
gives me correct result: Value within Function: newvalue2
I am not sure whether this is a general VBScript behavior and I am making a mistake in hoping to change array values in this 'dirty' manner or whether this is strictly HP-UFT (Unified Functional Testing) related, since this is where I could observe this.
I am not a profficient VBScripter either so I appreciate any help.
This is a documented behaviour
Argument in a Class
If the parameter is specified as ByRef, the argument is passed by
value if the variable sent as an argument is in a class
A simple VBA function. When I try to use it in my worksheet, all I get, no matter what I do, is "That name is not valid". I'm out of ideas.
Sub FindABV(temperature)
With Worksheets("Sheet1")
.Range("C28").GoalSeek _
Goal:=temperature, _
ChangingCell:=.Range("B28")
End With
FindABV = .Range("B28").Value
End Sub
I've tried creating a new Module to put it in. No change.
And no error indications from the code editor.
The Sub procedure performs a task and then returns control to the calling code, but it does not return a value to the calling code.
See more here.
This said, you cannot set a procedure equal to something:
FindABV = .Range("B28").Value
because that name is not valid (you cannot say that a procedure is equal to a certain value, it doesn't make sense). You probably wanted to use a Function to return the value of that cell calculated by the Goal Seeker depending on the input temperature that you pass by the function:
Function FindABV(temperature)
With Worksheets("Sheet1")
.Range("C28").GoalSeek _
Goal:=temperature, _
ChangingCell:=.Range("B28")
End With
FindABV = .Range("B28").Value '<-- return the value
End Function
However, be careful: if =FindABV(temperature) lies on Sheet1.Range("B28"), you will have a circular reference because your function will try to have the value of itself.
Your code will not deliver the results you want. If you want to have the Function work for different values than the ones stored in B28 and C28 you'll have to write it more like this:
Public Function FindABV(goalCell As Range, changeCell As Range, temperature As Double)
goalCell.GoalSeek Goal:=temperature, ChangingCell:=changeCell
FindABV = changeCell
End Function
But this doesn't matter in any case because GoalSeek actually changes the value in the ChangingCell which Excel will not do if it is called from within a Function.
I've been practicing some Ruby meta-programming recently, and was wondering about assigning anonymous classes to constants.
In Ruby, it is possible to create an anonymous class as follows:
anonymous_class = Class.new # => #<Class:0x007f9c5afb21d0>
New instances of this class can be created:
an_instance = anonymous_class.new # => #<#<Class:0x007f9c5afb21d0>:0x007f9c5afb0330>
Now, when the anonymous class is assigned to a constant, the class now has a proper name:
Foo = anonymous_class # => Foo
And the previously created instance is now also an instance of that class:
an_instance # => #<Foo:0x007f9c5afb0330>
My question: Is there a hook method for the moment when an anonymous class is assigned to a constant?
There are many hooks methods in Ruby, but I couldn't find this one.
Let's take a look at how constant assignment works internally. The code that follows is extracted from a source tarball of ruby-1.9.3-p0. First we look at the definition of the VM instruction setconstant (which is used to assign constants):
# /insns.def, line 239
DEFINE_INSN
setconstant
(ID id)
(VALUE val, VALUE cbase)
()
{
vm_check_if_namespace(cbase);
rb_const_set(cbase, id, val);
INC_VM_STATE_VERSION();
}
No chance to place a hook in vm_check_if_namespace or INC_VM_STATE_VERSION here. So we look at rb_const_set (variable.c:1886), the function that is called everytime a constant is assigned:
# /variable.c, line 1886
void
rb_const_set(VALUE klass, ID id, VALUE val)
{
rb_const_entry_t *ce;
VALUE visibility = CONST_PUBLIC;
# ...
check_before_mod_set(klass, id, val, "constant");
if (!RCLASS_CONST_TBL(klass)) {
RCLASS_CONST_TBL(klass) = st_init_numtable();
}
else {
# [snip], won't be called on first assignment
}
rb_vm_change_state();
ce = ALLOC(rb_const_entry_t);
ce->flag = (rb_const_flag_t)visibility;
ce->value = val;
st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce);
}
I removed all the code that was not even called the first time a constant was assigned inside a module. I then looked into all the functions called by this one and didn't find a single point where we could place a hook from Ruby code. This means the hard truth is, unless I missed something, that there is no way to hook a constant assignment (at least in MRI).
Update
To clarify: The anonymous class does not magically get a new name as soon as it is assigned (as noted correctly in Andrew's answer). Rather, the constant name along with the object ID of the class is stored in Ruby's internal constant lookup table. If, after that, the name of the class is requested, it can now be resolved to a proper name (and not just Class:0xXXXXXXXX...).
So the best you can do to react to this assignment is to check the name of the class in a loop of a background worker thread until it is non-nil (which is a huge waste of resources, IMHO).
Anonymous classes don't actually get their name when they're assigned to a constant. They actually get it when they're next asked what their name is.
I'll try to find a reference for this. Edit: Can't find one, sorry.
I have written a function that returns a User Defined Type.
How can i return a empty UDT in case of any error from the function?
I tried setting function to 'Nothing',but it is throwing 'Object Required' error.
Thanks in advance.
If at all possible, use a Class/Object instead. Even doing something as simple as turning this type:
Public Type EmpRecord
FName As String
LName As String
HiredDate As Date
End Type
into a class can be done by adding a Class to your project called EmpRecord and including just this in it:
Public FName As String
Public LName As String
Public HiredDate As Date
Then you can return Nothing from a function that gets an error while retrieving the record.
In VB6, a user-defined type is a "value type", while a class is a "reference type". Value types are typically stored on the stack (unless they're a member of a class). Reference types are stored as a pointer on the stack pointing to a place in the heap where the actual instance data is stored.
That means a reference to a class can be Nothing (the pointer is zero), whereas a value type can't.
There are multiple ways to solve your problem:
Add a Boolean member to your user-defined type to indicate success or failure.
Create another "wrapper" UDT like (see below) and return it from your function.
Change your UDT into a class, which can be Nothing (as tcarvin said).
Write the function to return a Boolean and take a ByRef parameter. The results are written to the parameter passed in if the function result is True. (A lot of people don't like this, but it's a common solution you should be aware of.)
Wrapper:
Public Type Wrapper
Success As Boolean
Inner As YourOriginalUDT
End Type
Function with ByRef:
Function Foo(ByRef Result As YourOriginalUDT) As Boolean
...
If Success Then
Foo = True
Result.A = A
Result.B = B
Result.C = C
... etc. ...
End If
End Function
A UDT can't be empty.
You can either use a "dummy" unintialised UDT, or just set all it's members back to the default values.