Late Binding - Myths and Reality
Written by Mike James   
Thursday, 21 October 2010
Article Index
Late Binding - Myths and Reality
Type
Casting
Real late binding

Conditional casting

At this point you are probably thinking that I’m cheating. In real late binding you really cannot know what the type is without using reflection to determine the runtime type.

True enough but, as the earlier argument indicates, the run time type of a late bound instance has to be one of a small number of possibilities, otherwise you couldn’t actually write the code at design time to handle it. In fact there is another alternative which allows there to be an unlimited number of alternatives but I’ll come back to this in a moment.

For example, you might have the possibility that there are two classes, Class1 and Class2 with Method1 and Method2 respectively and which one is late bound is arbitrary. Such an example really needs reflection-based late binding. In fact it is just as simple to handle using casting, but this time conditional casting.

First introduce Class2 to the example:

class Class2
{
 public string Method2()
 {
 return "Hello Later";
 }
}

Its Method2 has a different signature and return type but this doesn’t make a great deal of difference.

We need a suitable mechanism for generating a type that I can’t possibly know until run time. Randomly creating either Class1 or Class2 seems to fit this bill:

object late;
Random rnd=new Random();
if (rnd.NextDouble() < 0.5)
{
 late = new Class1();
}
else
{
 late=new Class2();
}

Now late references either Class1 or Class2 with a 50% probability of either. Of course the solution to the problem is to simply try to cast to Class1 or Class2 and call the method corresponding to the one that works!

Class1 temp1 = late as Class1;
if(temp1!=null)
{
 int count = temp1.Method1("Hello World");
}
else
{
int count=0;
}

Class2 temp2= late as Class2;
if(temp2!=null)
{
 String message = temp2.Method2();
}
else
{
 String message="";
}

This code works and it doesn’t produce any run time errors even if late turns out to be a reference to something other than the two classes in question. So in practice it isn’t any worse than using reflection or dynamic and in that case you would still have to test to discover which of Class1 or Class2 you had at run time.

It is also reasonable to say that conditional casting is a more strongly typed approach than reflection because at each stage you are stating your run time type assumptions and what happens if you are wrong – it really is type-based.

Of course you can invent more logical and neater ways to code the general idea. For example:

if (late is Class1)
{
 int count = ((Class1)late).Method1(
                         "Hello World");
}
if (late is Class2)
{
 String message =((Class2)late).Method2();
}

Inheritance and conditional casting

You may still not be happy with the example because in practice late binding is usually associated with a hierarchy of classes rather than a mutually exclusive choice between a small number of incompatible classes.

For example, if we change Class2 to be:

class Class2:Class1

Class2 now has a Method1 member and, from the point of calling Method1, it doesn’t matter if we treat Class2 as itself or as an example of Class1. For example:

if (late is Class1)
{
 int count = ((Class1)late).Method1(
                       "Hello World");
}

results in Method1 being called irrespective of whether or not late is Class1 or Class2. The reason is that the “is” operator returns true if late is of type Class1 or can be safely cast to Class1.

There is the small matter of polymorphism to consider in all of this.

For example, if Class2 overrides Method 1 as:

public new int  Method1(string text) 
{
 return 2 * text.Length;
}

i.e. returning twice the length of the string, then which method you call for a Class2 object depends on whether you treat it as a Class1 object when you get the original method or a Class2 object when you get the new method. That is it matters what type you cast the object to.

In other words if late is a reference to a  Class2 object:

int count = ((Class1)late).Method1("Hello");

calls the method defined in Class1 and if you use:

int count = ((Class2)late).Method1("Hello");

this calls the method in defined in Class2.

Also notice that the result of the cast isn't changed if Method1 is virtual and overriden in Class2. The difference between virtual and non-virtual only changes which method is called when the referencing variable type is Class1 and the object referenced is Class2. That is if late is a reference to a Class2 object then what you get when you write:

Class1 temp = (Class2)late; 
int count=temp.Method1("Hello");

depends on how Method1 is declared. If it is non-virtual then the call to Method1 uses Class1's definition even thought the object is of type Class2. For non-virtual methods the method called depends on the design time type of temp. However if Method1 is virtual in Class1 and overridden in Class2 then it is Class2's version of the method that is called. That is for virtual methods the method called depends on the runtime type of the object referenced by temp.

And yes this is complicated as the behaviour all depends on whether or not you assign your cast to another variable.

If you use dynamic for the late reference then the behaviour is more or less the same. Which method you call is determined by the runtime type of the instance. That is:

dynamic late;
...
late.Method1("Hello");

results in Class1's Method1 being used if late is a reference to a Class1 object and to Class2's Method1 if it is a reference to a Class2 object. The casts are implied and once again virtual/non-virtual makes no difference unless you assign the cast to another variable before using it.

<ASIN:1430225491>

<ASIN:0521721113>

<ASIN:0470447613>

<ASIN:1933988924>



Last Updated ( Thursday, 21 October 2010 )
 
 

   
RSS feed of all content
I Programmer - full contents
Copyright © 2014 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.