The conception, birth, and first steps of an application named Charlie

Subscribe: Atom or RSS

Russian Dolls and X-ray Specs

by Alister Jones (SomeNewKid)

In an earlier entry titled ‘The Cache is a Shadow, Not a Box,’ I discussed how an incorrect mental image played havoc with Charlie. It may come as no surprise that another incorrect mental image has caused yet more problems.

The mental image I have of object-oriented inheritance is that of Russian Dolls. Here is a little bit of code to provide an example of how I see inheritance working:

public class MediumDoll
{
    private Object SmallDoll;
}

public class LargeDoll : MediumDoll
{
}

To put the code into words, I see the private SmallDoll as being inside its containing MediumDoll. If LargeDoll inherits MediumDoll, then I see the SmallDoll as being deep within LargeDoll. Because SmallDoll is of private scope, LargeDoll cannot access it directly. But even if LargeDoll cannot access the SmallDoll, the SmallDoll is still inside the LargeDoll—but with the MediumDoll separating the two.

If you know the basics of reflection in .NET, you will know that it allows us to both see and use members that are otherwise hidden from view. Without reflection, SmallDoll would be completely hidden from any code outside of MediumDoll. But with reflection, we can see and use SmallDoll even from outside of MediumDoll. A completely unrelated class, such as ToyMaker, could employ reflection to see and use the SmallDoll that is otherwise hidden inside MediumDoll.

Because reflection gives our code x-ray specs, I believed that if I pointed reflection at the LargeDoll, I could see through to the SmallDoll. This is not the case.

Putting the analogy aside for a moment, what I was trying to do was rectify a weakness in Charlie’s Entity System. In writing Charlie’s First Code, I gave each entity an ID value, and a public method that changed that ID value.

namespace Charlie.Framework.Business
{
    public class Entity
    {
  
        public Int32 Id
        {
            get
            {
                return this.id;
            }
        }
        private Int32 id = -1;

        //  
        //  While this method has the same scope (public) of the Id
        //  property, we'll use a separate method to set the Id, as
        //  the Id property is properly meant to be a read-only
        //  property from the point of view of all consuming code.
        //  While we could use reflection to "hide" this SetId method
        //  as private, that seems like needless complexity.
        //  
        public void SetID(Int32 id)
        {
            this.id = id;
        }
              
    }
}

After an entity is retrieved from the database, its ID value should not be changed, which is why its ID property is read-only. But as an entity is being retrieved from the database, there needs to be some way to set that ID value. For this reason, I kept the ID property as read-only, but gave the class a separate SetID method. In the notes I admitted that this was a hack to avoid the complexity of using reflection to set an otherwise read-only value.

Inspired by the success of using reflection to inspect Charlie’s Bucket Full of Plugins, I decided to finally get rid of that little SetID hack.

Here then is a concrete example of the Russian Doll analogy:

public class Entity
{
    private Int32 id;
}

public class Article : Entity
{
}

What I needed to do was update Charlie so that if it was given an Article that had been retrieved from the database, it could set the private id field. The id field is inside the Entity class, from which the Article class derives. To repeat, I believed that reflection would give Charlie the x-ray specs needed to see through the Article to the private id field hidden within. Here is a cut-down version of the code I tried:

FieldInfo field = article.GetType().GetField("id");
if (field != null)
    field.SetValue(entity, 3);

The code says, “For this article, grab the field named ‘id’, and set its value to 3.’ This did not work.

I firmly believed that if given an Article (or a LargeDoll), reflection should allow me to see through to the private id field (or a SmallDoll). My persistent mental image of reflection as x-ray specs meant that all of my debugging efforts were directed at the x-ray specs. There are many ways to fine-tune the GetField method shown above, including a promising-looking FlattenHierarchy option. Yet every attempt failed.

After failing continuously to set the private id field, I realized that my concept of reflection as x-ray specs must be wrong. (That seems obvious in retrospect, but we are typically unaware of the mental images that we are using.) So once I became aware that I was using a mental image of x-ray specs, I put it to one side and looked instead at the Russian dolls. Specifically, I changed the code to “open” the dolls until it got down to the tiny doll within, at which point the reflection would work to peek inside. Here is a simplified version of the code that did work.

Type type = article.GetType();
while (type != typeof(Entity))
{
    type = type.BaseType;
}
FieldInfo field = type.GetField("id");
if (field != null)
    field.SetValue(article, 3);

The emboldened code keeps opening a derived class until it gets down to the base Entity class (keeps opening dolls until it gets down to the MediumDoll), at which point the reflection can see inside and change a private member.

I am a little loathe to publish this weblog entry, as I feel sure that I am missing something. In reading about reflection, I have never before seen a discussion about unravelling derived classes in order to see and use private members. Still, this weblog represents an honest account of Charlie’s development, and this does represent another little step.

by Alister Jones |  

5 comments

______
Anonymous Anonymous said...  
 

I'm happy to see that you are back.

______
Anonymous Anonymous said...  
 

Just a thought about the id property you want to set only when retrive from the database.

If you create your entity after the data has been retrived from the database, you can use a overloads constrictor of entity, wich accept a ID.

Exemple
public class Entity
{

______
Anonymous Anonymous said...  
 

public class Entity
{

public Entity (int id)
{
Private_id = id;
}

}

And then for inheritance
mybase.new (id)

I think

But this method is only usable if your entity can be created after you have retrive the id.

Ghislain

jahed_g (at) hotmail.com

______
Blogger Philip Smith said...  
 

Your Russian dolls analogy is a mis-representation of OO inheritance. Russian Dolls implement an approach commonly used to fake inheritance in non Object Oriented languages, called (strikingly for your analogy) "Containment".

For inheritance you need to think in therms of "Type Of"..

A medium Sized doll is not a Type of Small Doll - unless it just ate a lot of cakes

You may more properly consider a Doll to inherit from Toy, and perhaps share fields like Manufacturer, CountryOfOrigin and yes perhaps Id.. but maybe there is a higher type in play here err Product that may have an Id property.

Now, if you set the access modifier of your Id field to protected, the following works.

GetField("id", BindingFlags.NonPublic|BindingFlags.Instance);

and no, you are not breaking containment because a subtype is a err Type of a base Type.

Hope this helps...
If you make your Id field available to

______
Blogger Alister said...  
 

Hi Matt,

You have said that you feel a little empty at having read so far and received so little. I understand. For my part, I feel very empty for having worked so long and achieved so little.

Looking back, I wish I did many things differently, both with Charlie and with this weblog. Soon I will write some closing entries for this weblog, where I talk about what went right, what went wrong, and what I learned along the way.

(By the way, I am a guy. The photo below was chosen to give my personal website a 'pretty face' with which to welcome visitors.)

Post a Comment

----