Page 2 of 4
The dynamic type was introduced in C# 4 and it extends VB's way of doing things in Strict off mode to C#. Basically if you declare a reference to be dynamic then this is like declaring it to be object but you can attempt to use any methods or properties you care to.
For example, assuming the same class definitions as before you can write:
late = new Class1();
int count = late.Method1("Hello World");
In this case the use of Method1 succeeds just like it does in VB in Strict off mode. As in that case if the method or property that you try to use doesn't exist then the result is a runtime error.
Reflection based late binding
Suppose that in the C# example we really need to use late binding in a complex and sophisticated way.
Then the standard solution is to use reflection to dynamically discover the type and the other properties of the instance that we want to make use of.
The key to this is the Type class in the System.Reflection name space, so add:
The first thing we need is a type object representing the instance stored in late:
Type T = late.GetType();
Next we need a parameter array containing the parameters we want to pass to the method we are about to call. In this case we need a single element containing the string:
object param=new object;
With all of this set up we simply use the InvokeMember method:
int count= (int)T.InvokeMember(
This calls the specified member “Method1”, using its specified type, i.e. a public instance method, using default bindings belonging to the object referenced by late passing the parameters in param.
This all works very nicely but guess what happens if you try to access a member that doesn’t exist. You generate a runtime error!
In this and other senses reflection-based late binding using either reflection or the newer dynamic type isn’t any better than the VB approach.
Also notice the strange double standards being applied to the late binding of the inputs - the method name and its parameters - and the rather more casual approach to the outputs - the object returned as a result.
Do we bother to use reflection to discover what the result is and to access it? No, we simply cast it to an int because we know what type is it.
You can use exactly the same approach in VB .NET as the classes are all the same. I have seen VB programmers use reflection in this way simply to avoid having to set strict to off – something they regard as an admission of defeat. I think the simple “strict off” approach is far better.
We all know the type
When you see a late binding example of this sort you have to try to imagine that you really don’t know the type being used at run time at design time – this is the whole point of late binding.
But wait a minute.
Suppose you accept this as the absolute truth, that we don’t know the type until run time.
How can you possibly know what members to expect? How can you fill in the missing “Method1” specification if you really don’t know the type that is being used until run time? In fact what use to you is an instance of an unknown type?
The fact of the matter is that you must know what the run time type is at design time to write any code that makes use of the object, even if you are using reflection.
If this is the case then why not take the same approach to the inputs as you do to the output. The object that Method1 returns is actually an int and a down cast from object to int solves the problem of using this “late bound” type completely. So why not use a cast for the method call?
For example the following very simple code achieves the same result reflection or dynamic type:
int count =((Class1)late).Method1(
As we know that late is actually an instance of Class1 we simply cast to that type and use the method we know it has.
What is more, you even get the advantage of IntelliSense prompting to select the method. Of course if we get it wrong and late isn’t of type Class1, or if Class1 doesn’t have a Method1, then we generate a run time error but then so do other approaches to late binding. It is also very easy to make sure that no runtime error actually occurs using:
Class1 temp = late as Class1;
int count = temp.Method1("Hello World");
The as operator casts to the type if it can or returns a null reference if it can’t.
You could also claim that this method of late binding is strongly typed. You state clearly what the expected run time type of the object is and what happens if you are wrong.
You can use the same approach in VB .NET using the CType function to down cast.