Assigning values to class

I have a customer class with a bunch of properties like LastName, FirstName, Phone, etc

I would like to loop through the class and assign values
something like

var fld as string="FirstName"
for each property in Customer
if property=fld then customer.value(fld = "Tim")

Next

how can this be accomplished?

TIA

Where is your instance of customer declared? And created? As in:

Var wiggy as customer     // Tell the compiler what wiggy is
wiggy = new customer      // Give wiggy an actual instance

Then you have to have some data to shove into the instance, as in:

wiggy.FirstName = "Joe"
wiggy.LastName  = "Bloggs"

Etc.

Creating the class allows the compiler to know what you’re talking about, but until you actually create one and fill in its properties, it’s like having it written on a bit of paper. Nothing more.

The sudo code above assumes the objects are already have an instance created.
My problem is passing the properties as a variable

There are a few solutions:

function SetPropertyByName(name as string, value as variant)
  Select case name
    case "FirstName"
      me.firstName = value
    case "LastName"
       me.lastName = value
    ...
    end select
end function

Based on what you have asked, I think you want to use Introspection, which will let you loop through all the properties of a class to determine their names.

I am using introspection and have no problem getting and looping through the properties, my problem is passing the property name as a variable like the fld variable in customer.value(fld = “Tim”)

AIUI, that is not possible.

Here’s some code I wrote a while back to do this using Introspection:

Function SetPropertyByName(extends o as object, name as string, newVal as variant)
' given an object instance, and a property name, such as "firstName"
' finds a property with the same name, and sets it to the value newVal

' has some error checking for invalid combinations, but may not catch every illegal situation


#pragma DisableBackgroundTasks

dim props() as introspection.PropertyInfo = Introspection.getType(o).GetProperties  // warning, can cause thread yield here!!!

dim p as introspection.PropertyInfo

for each p in props
  if p.name = name then

     ' we found the property with the same name,
     ' lets do some error checking before setting the value

    ' type-safety when assigning
    dim t1 as Introspection.TypeInfo = p.propertyType
    if t1 is nil then
      system.debugLog CurrentMethodName + " t1 = nil"
      raise new NilObjectException
    end if
    
    if newVal is nil or newVal.type = Variant.TypeObject then
      system.debugLog CurrentMethodName + " invalid object assignment " + name
      raise new TypeMismatchException
      
      if t1.IsPrimitive or t1.isEnum then
        ' object or nil can not be assigned to primitive 
        system.debugLog "SetPropertyByName: object type mismatch : " + t1.fullname + " <> " + newVal.StringValue
        raise new TypeMismatchException
      else
        ' do the object types match?
        dim t2 as  Introspection.TypeInfo = Introspection.getType(newVal.ObjectValue) // note: will be nil if it's a basic type (string, integer, etc.)
        if t2 is nil then
          system.debugLog CurrentMethodName + " t2 = nil"
          raise new NilObjectException
        end if
        
        if t1.fullName <> t2.fullName then
          system.debugLog "SetPropertyByName: object type mismatch : " + t1.fullname + " <> " + t2.fullName
          raise new TypeMismatchException
        end if
      end if
      
    else
      // newVal is a primitive or enum
      
      if t1.IsEnum then
        // ok
      elseif t1.IsPrimitive then
        ' variant primitive -> primitive or enum  is OK
        
      elseif not (newVal is nil) then
        ' variant primitive -> object : not allowed
        system.debugLog "SetPropertyByName: object type mismatch : " + t1.fullname + " <> " + newVal.StringValue
        raise new TypeMismatchException
      end if
    end if
    
    ' if we reach here, it should be OK, so set the value now    
    p.value(o) = newVal
    
    return
  end if
next

' if we get here, we failed to find matching property name
system.DebugLog "Object.SetPropertyByName: missing property : " + name
break
raise new InvalidArgumentException

end function

PropertyInfo.name is a string - if the property is MyClass.FirstName then it’s propertyInfo will be a string “FirstName” so you can just match on that. See my code above.

Edit to add - if you use my function above, then your code would be quite simple:

var fld as string="FirstName"
customer.SetPropertyByName(fld, "Tim")

it could even be done in a single line:

customer.SetPropertyByName("FirstName", "Tim")

The main disadvantage to using Introspection? It is slow - possibly 10x or 100x slower than setting the property directly. If you have a lot of data and need high performance, the Switch/Case example above will be much faster.

We created a Meta class that, upon instantiation, stores the Introspection.PropertyInfo in a Dictionary upon first instantiation, then stores the Meta in a shared property. To set that property, we then do something like:

var pi as Introspection.PropertyInfo = Class.Meta.Value( "FirstName" )
pi.Value( Class ) = newValue

We’ve had no performance issues this way.

2 Likes

customer.SetPropertyByName(“FirstName”, “Tim”)

Is what I am looking to do. But I can hard code the properties if introspection is going to slow it that much.

I would try using Introspection first.

Computers are so fast these days that even 10x or 100x slowdown may not matter.

Beware premature optimization is the root of all evil

I am trying to wrap my head around this meta class thing I understand how to get the property info into a dictionary upon instantiation. I guess I am at a loss with the whole shared properties coding methods.

[ @Kem_Tekinay please correct me if I’m wrong ]

I believe that Kem’s solution is an optimization of my solution, which avoids having to loop over all the propertyInfo object array every time you make an assignment.

Technical info: looping over a list or an array to find an item in it takes longer as the array grows longer, where N is the # of items in the list. This is called Order N or O(N) under the Big O Notation

Dictionarys tend to have a (mostly) constant time for accessing an item, regardless of how many items are in the dictionary.

This is called constant, Order 1 or O(1).

I would not worry about this for now, unless you have poor performance using my solution.

If that happens, come back and @Kem_Tekinay will solve it for you :wink:

1 Like