Handling object properties on the fly!
Publishing object properties with .NET
The problem
A class created with a programming language – whatever this programming language is –poses the problem of requiring a programming language to access the properties of the class thus created.
For example:
  • Let us imagine a class (html_article), written in Visual BASIC, and having for properties:
    • Title
    • Width
    • Height
  • Let us suppose that the class offers one interface (in the form of a DLL for example) allowing others programmers to create and manage objects of this class...
  • Via this interface, before .NET, the class was accessible only to Visual BASIC programmers... with .NET, it became accessible to all .NET programmers (C++, C#, VB, JAVA...)... a great progress!

However, until now, the class remains accessible only to programmers by means of writing and manipulating code...

How to allow a user (not necessarily programmer) to dynamically handle properties of objects of this class?

For example, how to allow a web site manager to set the article’s title of html_article class to the active session’s user without having to write code to do that?

Also another question: What to do when the class gets enriched with new properties? Or when certain properties change access parameters?

I was confronted with this problem while working on easySite.NET... Here is how I tried to solve it.
The class in the user interface
Databases are excellent tools for persisting and to storing information, and also for binding them in a robust and efficient manner.

In the suggested solution, the user defines the object "html_article" and describes its properties in a database similar to the following:

Html_article object: strawberry pie
Prop_name Prop_value
Title Tarte aux fraises
Width 85%
Height 100%

A module of the solution was given the responsibility to read this information, to create the object and to assign the desired attributes to it...

One of the problems in this module was:
How to swap from the text information read in database, to one instruction like: objet_article.Title="Tarte aux fraise " ?

One solution (not very elegant, but quite efficient!) was to write a select case bloc:

Select case prop_name
    Case “Title”
        object_article.Title =prop_value

    Case “Width”
        object_article.Width =prop_value

    Case “Height”
        object_article.Height =prop_value
End select

System.Reflection.PropertyInfo
.NET offers some classes which allow a more realistic dynamic solution, and more elegant than the preceding code.

The class Type (System.Type) allows us to access properties of a given class by property name like in the example:

Dim Type_class_article As Type = object_article.GetType()
Dim PropInfo As PropertyInfo = Type_class_article.GetProperty("title")


The class PropertyInfo (System.Reflection.PropertyInfo) also contains a SetValue method which allows us to modify the property value.

SetValue The syntax:
PropertyInfo.SetValue(
      ByVal obj As Object, _
      ByVal value As Object, _
      ByVal index() As Object )


Parameters

Obj Instance of the object containing the property to be set.
Value The value to be assigned to the property.
index Optional: index if the property is indexed, otherwise null (Nothing).

One can thus use the PropertyInfo class to assign values to the properties without knowing their names in advance.

Several conditions however:
  • The property must exist and must be public;
  • The property should not be read only;
  • The data type of the value to assign must identical to the property’s data type.

Any way, that would enable us to read properties of the class (from the database) in the form: prop_name / prop_value and to assign the values obtained using a code like the following:
Dim class_Type As System.Type
Dim prop_info As System.Reflection.PropertyInfo

‘//////////////// obtain class type ////////////////////////////////
class_Type = object_article.GetType()

‘//////////////// obtain the property //////////////////////////////
prop_info = class_Type.GetProperty(prop_name)

‘//////////////// assign the valure to the property //////////////
prop_info.SetValue(object_article, prop_value, Nothing)

A general purpose function
This ‘recipe’ enables us now to write a general purpose function which assigns a value to a property of any class:

Sub set_object_property(ByRef obj As Object, _
          ByVal prop_name As String, _
          ByVal prop_value As object )
   Dim class_Type As System.Type
   Dim prop_info As System.Reflection.PropertyInfo

   class_Type = obj.GetType()
   prop_info = class_Type.GetProperty(prop_name)
   prop_info.SetValue(obj, prop_value, Nothing)
End Sub

Dynamically loading objects and their properties
Now that this generic function exists, all the ' loaders’ of objects of our various classes can to call it to assign values for user defined properties stored in the database (or defined by any other means)
Here a sample of database structure for handling this question:



  • A ‘properties table’ stores property names of the articles class;
  • Another table stores property values for each article.

When the user creates an article, he or she selects and assigns the values to the desired properties.

When the ‘article’ class evolves and comes with new properties, we just have to add these new properties to the database table to have them available for the user.
Code example for loading an object and its properties
‘--------- loading an object from the database --------------------------------
Sub auto_load( obj_id As long)
    ‘////// load object information
    ‘ code pour loading object information…
    ‘////// load customized property values
    Apply_properties()
End Sub


‘--------- load and assign object’s property values ---------------------
Sub Apply_properties()
    Dim connect As New OleDb.OleDbConnection(m_str_connect)
    Dim cmd As New OleDb.OleDbCommand
    Dim dr As OleDb.OleDbDataReader
    Dim prop_name AS String
    Dim prop_value As string

    '////// obtain properties recordset
    cmd.CommandText    = "SELECT prop_name, prop_value " _
            & " FROM obj_properties_qry " _
            & " WHERE(obj_id =" & m_id.ToString() & ") "
    cmd.Connection = connect
    dr = cmd.ExecuteReader(CommandBehavior.Default)

    '///// read and assign property values
    Do Until dr.Read() = False
        Prop_name = dr.GetString(dr_load.GetOrdinal("prop_name"))
        prop_value = dr_load.GetString(dr_load.GetOrdinal("prop_value"))

        ‘//// call our general purpose function
        set_object_property ( Me, prop_name, prop_value)
    Loop

    dr.Close()
    cmd.Dispose()
    connect.Dispose()
End Sub

Error handling
Obviously, our current version of the general purpose function set_object_property is a little bit simplistic, because it is entirely unaware of error handling!
.NET offers efficient mechanisms making it simple to trap exceptions... We will use Try / Catch to try to detect and to trap errors or exceptions:

Dim class_Type As System.Type
Dim prop_info As System.Reflection.PropertyInfo

‘///// try to obtain the type of the object class
Try
    class_Type = obj.GetType()
Catch ex As Exception
    Err.Raise( vbObjectError + 1210, "Couldn’t obtain object class type", _
        "Error details: " & vbCrLf & ex.Message)
    Exit Sub
End Try

‘/////// try to obtain the property
Try
    prop_info = class_Type.GetProperty(prop_name)
Catch ex As Exception
    Err.Raise( vbObjectError + 1210, _
        "Couln’t obtain object property:" & prop_name, _
        "Error details: " & vbCrLf & ex.Message)
    Exit Sub
End Try

‘////// try to assign the value to the property
Try
    prop_info.SetValue(obj, prop_value, Nothing)
Catch ex As Exception
    Err.Raise( vbObjectError + 1210, _
        "Couldn’t assign the value of property:" & prop_name, _
        "Error details: " & vbCrLf & ex.Message)
    Exit Sub
End Try


Conclusion
Assigning values to object properties using properties’ names, offers several advantages:
  • Allows the user, in a simple and transparent manner (through a database, a file or another means), to interact with properties of objects (classes) without having to write or change applications’ code;
  • Allows dynamic object creation procedures to manipulate object properties without having to know in advance the details of any of their classes;
  • An interesting flexibility to face the impact of classes evolution;