Willy’s Cave Dwelling Notes #3 – C# … re-visiting some interesting features
Continued from Willy’s Cave Dwelling Notes #2 – Windows Azure, we do a brief context switch from clouds to Visual Studio C#. Before I delve into asynchronous programming in C# 5, I first want to refresh some of the features introduced in previous compilers.
The sample code used in this blog post can be obtained from the https://vsarguidance.codeplex.com project. Look for the WillyCaveDwellingNotes.zip file in the Sample Code download.
Interesting Features in C# prior to v5
Get|Set
The property getter and setters allow us to implement protective logic to read from and write to class fields. Often, however, our code is littered with unnecessary “default” implementations of the properties as shown in lines 28-37 below. C#3 introduced a new syntax for properties, called auto-implemented property, which create the same plumbing behind the covers. It is visually evident that the same class, using the new syntax in lines 57-58 is a more compact and much simpler … and we all know that we strive for simplicity
On the side … another simplification I noticed when writing the sample code, is the different ways of calling the constructors and passing field values. Personally I prefer option 2 (line 100) over option 1 (lines 92-97), but that’s just a personal preference.
NOTE: Compiler will fail as we have to select option 1 or 2, or face an error of type “Type '…' already defines a member called '…' with the same parameter types”.
Parameters
Optional Parameters
C#4 introduced optional parameters, which help us improve code clarity, especially when working with COM interfaces. The optional parameter allows us to define defaults for some or all of the parameters at the end of the parameter list. In our sample below, we are specifying testValue and testText as optional parameters, which means that we can call the method passing one, two or three parameters.
Time to peek into the IL with reflector, where we notice the [opt] attribute:
If you ever wondered what all the IL is about, you can enjoy https://www.ecma-international.org/publications/standards/Ecma-335.htm as bed-side reading. Using the Partition III CIL Instruction Set section of the publication, we can clarify some of the instructions above:
ldarg load argument onto the stack ldstr load a literal string box convert a boxable value to its boxed form nop no operation
ldarg – load argument onto the stack
ldstr – load a literal string
box – convert a boxable value to its boxed form
nop – no operation
Named Parameters
Named parameters, especially used in conjunction with optional parameters, allow us to create more readable code (clarity). Some documentation also mentioned the ability not having to remember the order of the parameters as a feature, but I am at two minds on this feature.
Looking at the code we can see the use of optional parameters in code line 77-79. In lines 83-85 we are using named parameters and also relying on optional parameters. Line 84 is an interesting one, because it shows us how to skip an optional parameter in the call, in this case testValue.
For the 80’s Assembler colleagues, we can show the corresponding IL:
When I stepped through the code, I was surprised to see that the call from line 78 and 85 both chose the generic method defined in line 35 and not line 40.
To cut a long story short, the compiler always looks for the shortest possible definition, which in this case is line 35.
dynamic versus object versus var keyword
We conclude todays C# exploration with a quick peek at the var, object and dynamic data types.
Data Type | Introduced | Description |
object | Dawn of C# | The mother of all objects. |
var | C# 3 / VS2008 | Inferred data type, which means that the compiler determines the appropriate data type at compile time. |
dynamic | C# 4 / VS2010 | Deferred data type, which means that the compiler defers all checks for resolution at runtime. |
If we create a quick sample …
… and look at the generated IL, we are left pondering as the IL code for both the calling and method code for the use of dynamic and var appears identical.
It is only when we hover our mouse arrow over the var and the dynamic variables that we notice a difference. IntelliSense explains to us that the var based variable is an implicitly typed string variable that is inferred by the compiler. The dynamic based variable bypasses all compile-time type checking and defers to the runtime.
Read https://msdn.microsoft.com/en-us/magazine/gg598922.aspx, by Alexandra Rusina, for a detailed exploration of the dynamic keyword.
While punching up the sample it became apparent that the var data type cannot be used as a parameter type or a return type, as shown below:
To highlight some of the magic, we changed the sample code as shown in lines 28-32. When we assign an object to a string, we are encouraged (forced) by the compiler to use a cast and infer
To highlight some of the magic, we changed the sample code as shown in lines 28-32. When we assign an object to a string, we are encouraged (forced) by the compiler to use a cast and infer the type. When assigning a dynamic to a string, however, the compiler sits back and delegates to the runtime.
The change behind the scenes only becomes apparent when we look at the IL as shown below, which shows that the dynamic data type is deferred for resolution at runtime using the dynamic language runtime (DLR) provided in .NET Framework 4.
To answer some of he questions I had when starting this adventure:
object | var | dynamic | Notes | |
Can be used as a method parameter? | yes | no | yes | |
Can be used as a method return type? | yes | no | yes | |
Can be changed dynamically (not statically typed)? | yes | no |
yes | A dynamic variable is resolved at runtime. |
Useful for? | We do not the data type at compile time | Anonymous types Less typing without loss of functionality | Interoperability Code, i.e. COM, Office Automation |
In the next adventure we will be looking at a C#5 feature, namely C# and Asynchronous Programing.
References: