Deep C# - Dynamic C#
Written by Mike James   
Thursday, 16 January 2020
Article Index
Deep C# - Dynamic C#
Static Typing
Anonymous Typing
Dynamic typing
Overloading

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



Last Updated ( Thursday, 16 January 2020 )