Dynamic C#
Written by Mike James   
Tuesday, 11 March 2014
Article Index
Dynamic C#
Anonymous types
Dynamic typing
Beyond .NET objects

Banner

 

Although this use of derived types in method calls is a little more complicated notice that it uses the declared type of each variable and not what the variable actually references.

That is which version of the method is called can always be determined at compile time. Another way of saying this is that by default all method calls are early bound.

In fact the only example of late binding in C# occurs when a method is declared to be virtual. In this case the method that is called does depend on runtime type, not of its parameters but on the runtime type of the class it belongs to. That is, if MyMethod isn't declared as virtual then:

MyObject.MyMethod();

will always call the MyMethod defined as part of what ever type MyObject is declared to be. In other words, you can read through the program's code until you find:

MyClass MyObject=New MyClass();

and then without examining the program any further you can conclude with 100% certainty that the version of MyMethod that will be called is the one defined as part of MyClass - even if MyMethod has been overridden in a class derived from MyClass.

That is if MyMethod isn't virtual then (notice that the variable is of type MyClass but the object it references is MyClass2:

MyClass MyObject=New MyClass2();
MyObject.MyMethod();

still calls the appropriate version of MyMethod defined as part of MyClass not any alternative defined in MyClass2. This is once again early binding as the method call is determined at compile time. That is the variable MyObject is of type MyClass so it is the MyClass version of MyMethod that is called no matter what MyClass2 does to it.

If, on the other hand, MyMethod is declared as virtual in MyClass and overriden correctly in MyClass2 then in this case late binding operates and:

MyClass MyObject=New MyClass2();
MyObject.MyMethod();

does call the new version of MyMethod as defined as part of MyClass2.

This is what the whole virtual/non-virtual distinction is about. All non-virtual methods are early bound according to the type of the variable holding the reference to the object but virtual methods are late bound according to the type of the object the variable references at run time. 

So apart from the use of virtual methods all binding in C# is early binding and only the declared type of a variable can influence what a program does.

As we will see dynamic typing promotes the determination of type to something that can determine what happens at runtime beyond the use of virtual.

But before we look at dynamic typing we need to take a look at a related feature that is often confused with dynamic typing - anonymous typing.

csharp

Anonymous typing

The most type-free statement you could write in C# 2.0 is something like:

object x = MyFunc();

which works no matter what type MyFunc returns. However, you can’t do anything with the returned object unless you cast it to a more appropriate type.

That is in most object oriented languages the top most class in the hierarchy, usually called object, can be used as a reference to any sub-class and in this sense using it is a way to make the language less type dependent. 

In C# 3.0 the anonymous type was introduced as an alternative to using object and the potential confusion began.

An anonymous type is strongly and statically typed in that the compiler works out its type at compile time and then applies all the usual strong typing rules.

The only complication here is that if the type implied by the code doesn’t actually exist as a named type the compiler will also generate a suitable name and type.

That is anonymous typing is still early binding in action and everything that happens is fixed at compile time.

Let’s start off with the simplest anonymous type. For example, given the function:

public int MyFunc() {
 return 1;
}

the statement:

var x = MyFunc();

allows the compiler to deduce that the variable must be an int. So after this you can use:

x = 2;

but the statements:

string i;
i = x;

will still result in a compile time type error as x is an int and i is a string. Anonymous types are still strongly typed at runtime and their type is deduced at compile time i.e. they are static types that the compiler infers from the static code.

A slightly more complicated situation is where the type is created “on the fly”:

var x = new {
          name = "Mike",
          Address = "AnyTown"
        };

In this case the new type doesn’t have a name and so the compiler creates one something along the lines of “AnonymousType#1”. 

Now you can use statements like:

string i;
i = x.name;

as not only has the type of the structure been determined so has the type of each of its fields.

A subtle point that is important not to miss is that an anonymous type created in this way is read-only so you can’t assign to any of its fields and any attempts to do so will be picked up by the compiler.

Notice that this is different from the behaviour when the inferred type already exists when the type is, unless, of course, the type is otherwise restricted to be read only.

For example, if you first declare the structure previously created on the fly:

public struct MyAdd {
  public string name;
  public string Address;
}

and change the function to read:

public MyAdd MyFunc(){
 return new MyAdd {
          name = "Mike",
          Address = "MyTown"
         };
}

then you can write:

string i;
var x = MyFunc();
x.name="new name";
i = x.name;

If you need even more proof that an anonymous type is strongly typed just notice the fact that the type and its fields are included in Intellisense prompting as you work with the code at design time!

It really is that simple. If you declare two anonymous types that have an identical field structure then the compiler is smart enough to notice that it needs to create only a single new type name but as the resulting objects are read-only you still can’t use assignment.

There are some restrictions on how you can use anonymously typed variables but they are all fairly obvious and reasonable.

In particular the anonymous variable has to be local, i.e have method scope. This means that you can still use them within for, foreach and using statements. 

Of course it has to be mentioned that anonymous types were introduced mainly to make LINQ look easier to use – but you can still use LINQ, and indeed everything in C#, without ever using the var statement.

Anonymous types are entirely a convenience and in no way a necessity as if the compiler can deduce the type of a variable at compile time - so can you!

 

Banner

<ASIN:0672336901>

<ASIN:1118314417>

<ASIN:1430242787>

<ASIN:1118833031>

<ASIN:0321658701>



Last Updated ( Tuesday, 11 March 2014 )
 
 

   
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.