XMLpitstop.com   |  VBnetexpert.com   |  Community Credit  
 
 
Pitstop Search:  
in
 
Sign in | Join | Help
 
 
  Blog
    Home  
 
  Entries By Date
 
<November 2008>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
 
 
  Blog Categories
   
 
  Archives
    December 2009 (2)  
    October 2009 (1)  
    September 2009 (1)  
    August 2009 (2)  
    July 2009 (2)  
    June 2009 (1)  
    May 2009 (1)  
    February 2009 (1)  
    December 2008 (1)  
    November 2008 (3)  
    September 2008 (3)  
    August 2008 (3)  
    June 2008 (4)  
    May 2008 (2)  
    April 2008 (3)  
    March 2008 (3)  
    February 2008 (5)  
    December 2007 (4)  
    November 2007 (1)  
    October 2007 (3)  
 
  Syndication
    RSS  
    Atom  
    Comments RSS  
  .NET Flea Market  
 

Casting Upwards

When binding business objects to a datagrid, often you have a need to display some information that is not directly exposed by the object itself.  Maybe it's a calculated value, maybe it's something nested deeper in the object.  When faced with this issue, there are a few different action paths you can take.  You can add extra read-only properties to your business object to support the extra view information.  You can create a new class that inherits from the class you are displaying and put the extra properties in there.  Or you can handle the CellFormatting event in the datagrid and change the displayed values manually.  One of the downsides of using a new derived class with extra properties is that you can't cast a base class to it.  You could cast down to the base class, but no casting up.

Here is a technique that is closest to the second option listed above and side-steps the upcasting problem.  I dislike the first option because it clutters the business object with UI-specific code.  Going with option 2 is only slightly better, while you can populate the correct display-specific object and return it from your business logic layer, either you have to have a method that return the derived type, or you will have to cast it to its correct type in the UI.  Even then, your business layer still contains UI logic.

So, keeping things separated, the derived display-specific class should be defined in the UI layer.  This means it will have extra read-only properties for use with databinding.  The business layer will return the basic object(s), so it will be up to us to convert these to UI-friendly versions.  There are two problems with converting the object: not all the object state may be exposed via public properties, and those properties may contain logic.  It would be best to copy the object by its internal state - private variables.

On first thought, working with the private variables means the code must be inside the source object and the destination object.  This would be tedious to do, passing in the destination object, then sending the source object's private variables to the destination so the destination object can manipulate its own private variables.  Yuck.  However, using Reflection, the job gets a whole lot easier.

Here's a small class with a method to convert one class to another by copying its private and public fields.  The properties are intentionally excluded since they may contain logic that modifies the internal state.  You should use this technique with care and know exactly what it does and does not do.  Basically, it copies values from one instance of a class to another.  This is fine for simple classes, but it's not going to resolve references for you.

Consider ClassA with a private field of type ClassB.  ClassB maintains a private variable with a reference to ClassA, so that it can manipulate all of its "parent's" state and logic.  If you use this technique to cast ClassA to ClassAA, because you want an extra property to display some info from ClassB, you're in for some fun results if you change some data in ClassAA.  This is because ClassB still has a reference to ClassA, not ClassAA.

Public Class UpCaster
    Shared Sub CastUp(ByVal sourceObj As Object, ByVal destinationObj As Object)
        Dim values As New Dictionary(Of String, Object)
        Dim props() As Reflection.FieldInfo 

        props = sourceObj.GetType.GetFields(Reflection.BindingFlags.NonPublic _
            Or Reflection.BindingFlags.Static _
            Or Reflection.BindingFlags.Instance _
            Or Reflection.BindingFlags.Public) 

        For Each p As Reflection.FieldInfo In props
            values.Add(p.Name, p.GetValue(sourceObj))
        Next 

        props = destinationObj.GetType.GetFields(Reflection.BindingFlags.NonPublic _
            Or Reflection.BindingFlags.Static _
            Or Reflection.BindingFlags.Instance _
            Or Reflection.BindingFlags.Public) 

        For Each p As Reflection.FieldInfo In props
            If values.ContainsKey(p.Name) Then p.SetValue(destinationObj, values(p.Name))
        Next 

    End Sub 

End Class
Published Nov 04 2008, 10:52 PM by anachostic
Filed under: ,
Comments

No Comments

About anachostic

That's me. Seek and ye shall find.
 
 
Copyright © . All Rights Reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems