f you’re one of the thousands of programmers out there writing server-side business components, then youve probably used data wrappers: light-weight objects designed to access streamed data. The following article builds on the traditional wrapper concept to create self-aware objects, which offer the added benefits of simplicity and re-use.
As any good component programmer will tell you, it is always important to minimize the number of calls between objects; and one of the ways we achieve this is to pack all of our data up into “streams” to pass it from one object to another. Instead of passing, say CustomerID, Name, and Email as separate properties, we wrap them up into a single string; perhaps an XML stream, like so:
1234 John Doe [email protected]
Often the easiest way to manage these strings in our code, is by writing a data-wrapper?a custom class, which gives access to all the pieces of data through COM properties: objCustomer.CustomerID, objCustomer.Email, and so on.
However, we also know that data wrappers can be a pain to write?stream and un-stream methods are fiddly (do this property, so that property, do the other property), and you have to re-write them from scratch every time, often by cutting and hacking code from similar objects elsewhere in the system. What a drag. Wouldnt it be nice if we could write a data wrapper once, and then re-use it in a variety of scenarios, with only minimal “two-minute” modifications? This article shows you how.
The solution is to write an object that discovers its own properties. That way, your stream and un-stream methods only have to be written once, and then you just add or remove properties to create exactly the wrapper you need. The solution uses a little-documented Win32 object?the Type Library Information component: TLBINF32.dll.
The Type Library Information component, which, if its not in your System32 directory, can be found on your Visual Basic 6 CD, provides some neat methods to explore the public interface of any COM object at run time. Try thinking of it as accessing VBs Object Browser in your code!
Its InterfaceInfoFromObject method exposes a Members collection, which will permit us to loop through all the members?i.e. public properties, methods and variables?of our object; and we will use it in our stream/ un-stream methods to loop though all of the properties of our wrapper one by one.
My example project references two external libraries: the MS XML object, to “stream” our wrapper to XML; and the Type Library Information component, to “discover” the public interface of our wrapper.
First of all we need some public properties for our wrapper, which express the attributes of our data.
I have created a simple class, and added three public variables.
Now, a traditional “stream” method for this object would look a little like this pseudo-code.
Stream = Stream & Me.CustomerIDStream = Stream & Me.NameStream = Stream & Me.Email
But I am going to write a stream method which loops through all of the properties, however many there are, and whatever their names, and packs them up into XML. The code below uses the Type Library Information object (TIL), which exposes all the public properties of the object (Me) as a collection of Members. As we loop through the Members collection (using a For Each construct), we expose the Name of each public variable in our class (objMember.Name)?ContactID, Email, etc.
We can then use VBs CallByName function to get the value of each of our public variables. You can find documentation about CallByName in the VB help files, but basically it is an alternative way of invoking an objects public properties, akin to late-binding with CreateObject.
S = CallByName (Me, "ContactID", vbGet) Is analogous to: S = Me.ContactID
Finally, having retrieved the value of the property, using CallByName, we use the XML object to append a node to a local document, which we will stream-out just before we exit the method.
And the un-stream method works the exact same way?looping through all of the members of the wrapper, and invoking the method by name to set its value.
Now I can do two things. I can continue to add more public variables to my class, and (without any extra work) they will be streamed and un-stream along with everything else. And, second, I can copy my XML property statements (my custom stream and un-stream methods) to a new class, to which I can add different variables, referencing a completely different part of the system: Orders, say, and I have a brand-new wrapper class in seconds.
Lets look at a concrete example.
Ill begin with the wrapper class described above. It has properties of CustomerID, Name and Email. As a new customer is entered at the user interface, an instance of our wrapper (XMLCustomer) is created, and each property is populated:
Inside MyBusinessObject, the SaveCustomer method reconstructs the wrapper object from the XML stream, and validates and saves the data:
Now, say I am asked to add a new item to our customer data?Country, for example. All I need do is go to my wrapper, and add the additional item as a new public variable.
Now I can reference this variable in all of my UI code, without any troubles at all, and it will be automatically included in the XML stream that is passed through to my business object.
As you can see, these data wrappers are easy to create, and even easier tomaintain. Of course, we must be aware that these kinds of techniques have their limitations. There is always a performance hit when running additional external objects; and it is not recommended to deal with very large documents, or hierarchical objects in this manner. Nevertheless, I hope these techniques inspire you to try something different in you coding