Each version of C# has a number of new features and generally a major
theme. The major themes have been generics and nullable types in C#
2.0, LINQ in C# 3.0, and dynamic types in C# 4.0. The major features
added in each release are generally considered to be the following:
- C# 2.0—Generics (.NET Framework support was added, and C# benefited from this); iterator pattern (the yield keyword); anonymous methods (the delegate keyword), nullable types, and the null coalescing operator (??).
- C# 3.0—Anonymous types, extension methods, object initializers, collection initializers, implicitly typed local variables (var keyword), lambda expressions (=>), and the LINQ query expression pattern.
- C# 4.0—Optional Parameters and Named Arguments, Dynamic typing (dynamic type), improved COM-Interop, and Contra and Co-Variance.
Dynamic Lookup
C# 4.0 provides access to the Dynamic Language Runtime (DLR) using
the new ‘dynamic’ keyword in .NET4, allowing dynamic languages like Ruby
and Python to expose their objects to C#. Apart from consuming objects
from dynamic languages, this feature also helps us in implementing
customized dynamically dispatched objects. This can be done by
implementing the IDynamicObject interface, which itself is usually done
by inheriting from the abstract DynamicObject class and providing our
own implementation and invocation; the IDynamicObject interface allows
us to interoperate with the DLR and implement our own behavior!
Before we can go into what Dynamic type is and how it acts, we need
to have a basic understanding about DLR and its components, so we’re
going to spend a bit of time investigating this new feature.
Dynamic Language Runtime (DLR)
The DLR is the new API in .NET Framework 4 that is responsible for
implementing dynamic programming, and is common runtime for the dynamic
languages. The C# runtime is built on the top of the DLR in order to
give provision for the dynamic typing. The below figure illustrates the
block diagram of the DLR and its internal components.
The languages with dynamic capabilities (such as C#4.0 and VB 10.0)
are built on top of the DLR which, as we can see above, has three main
components at it’s core:
1. Expression Trees
2. Dynamic Dispatch
3. Call Site Caching
An Expression Tree depicts code in the form of a
tree, which allows languages to be translated into a standard design on
which the DLR can operate. These are the same kind of expression trees
that were introduced in C# 3 LINQ, but which have now been improved to
support statements. Once code is in a tree representation, the DLR can
take the tree and use it to generate CLR code.
Dynamic Dispatch is the process of mapping messages
to sequences of code at runtime . This is the way that the system lets
the binders decide on the target method. Code is generated for dynamic
invocations to the appropriate Language Binders.
Call Site Caching is used to avoid the need to call
into the binder. Normally the binder returns an expression tree which
the DLR compiles, but this step can be avoided if the types of the
arguments are the "same".
Speaking of the binders, these exist beneath the
DLR, and are responsible for communicating with the respective
environments of different technologies. For example, the Object binder
allows communication with .NET Objects, the JavaScript binder allows
communication with JavaScript in Silverlight, the Python and Ruby
binders allow to communication with their respective languages, and the
COM binder allows communication with Office / COM Objects.
All of this is wrapped up in the DLR, which C# 4.0 provides access to
using the new ‘dynamic’ keyword. This permits data types to be decided
dynamically at runtime, as opposed to statically at compile-time, by
redirecting any calls involving a parameter of type dynamic through the
DLR. Dynamic type signifies to the compiler that all operations based
on that type should (unsurprisingly) be inferred dynamically, and
instructs the compilerto ignore the compile time checking for this type.
The C# compiler now allows for calling a method with any name and any
arguments on dynamically created object types. Consider the code below.
dynamic d = GetNum();d.divide(40,5); // allows us to call any method with any signature..
As d is declared as dynamic, the compiler will not
generate any runtime errors for the above declaration and, although it
will still engage in type checking, it will not decide the target data
type of the call until runtime; so the actual object that is being
dynamically referred to will be determined at runtime. As mentioned in
the code annotation above, the compiler allows calling dynamic objects
with any method or signature. Here is diagrammatic representation of how
it works:
Because C# is a statically typed language, the ‘dynamic' type informs
the compiler that it is working with a dynamic invocation, and so can
forget about the normal compile-time checking for that type. However,
this also means that illegal operations (if any) will only be detected
at runtime.
The Difference between Var and Dynamic
People often get confused between var and dynamic, so I would like to you to understand exactly what is meant by each keyword.
If the ‘var’ keyword is used, the data type is still determined by
the compiler at compile time. On the other hand, when the ‘dynamic’
keyword is used, the member and method lookups are determined at
runtime. In addition, dynamic can also be used as the return type for
methods, and the Var keyword cannot be used for procedure return calls.
In addition, the dynamic keyword will not give you trouble if it
doesn't have any associated method. On the other hand, var will never
allow the application to compile if any method is used which is not
associated with it.
Optional Parameters
Microsoft’s coevolution in C# and VB languages has made this feature
possible now. These parameters need to be declared with a default value
in the method signature, and allow for omitting arguments to member
invocations. The below example describes the syntax:
private void CreateNewStudent(string name, int studentid = 0, int year = 1)
The method above can be called in any of the following ways:
CreateNewStudent("Sukanya"); //Equivalent to Sukanya,0,1CreateNewStudent("Prakash", 16); //Equivalent to Prakash,16,1CreateNewStudent("Pinal", 40, 2); //Equivalent to Pinal,40,2
In the above code, it is mandatory to pass the name, but the
remaining two parameters are optional. If we do not pass any of the
values in those parameters, then the default values are passed.
Note: The Optional Parameters must be placed after the required parameters, or else the C# compiler will show a compile time error.
There are a few limitations to the optional parameters feature, and
we’ll look at them after we’ve considered the new Names Arguments
feature, as the two are very useful when deployed together..
Named Arguments
Named arguments are a way to provide an argument using the name of
the desired parameter, instead of depending on its [the parameter’s]
position in the parameter list. Now, if we want to omit the studentid
parameter value in the above code, but specify the year parameter, the
new named arguments feature (highlighted below) can be used. All of the
following are also valid calls:
CreateNewStudent("Jacob", year: 2);CreateNewStudent(name: "Andrew", studentid: 30, year: 2);CreateNewStudent("Vamshi", studentid: 4);CreateNewStudent(year:2, name:"Hima", studentid: 4); //changing the order
Named arguments are the best way to write self-documenting calls to
your existing methods, even if they don’t use optional parameters. Not
only can an argument use the name of the relevant parameter, but we can
also change the position of the parameter if desired.
The example below shows how to make use of optional and named arguments:
private static void CreateNewStudent(string name, int studentid = 0, int year = 1){
Console.WriteLine("Name = " + name + " : "+"StudentID = " + studentid + " : "+"Year = " + year); }static void Main(string[] args){
CreateNewStudent("Sukanya");CreateNewStudent("Prakash", 16); CreateNewStudent("Pinal", 40, 2);CreateNewStudent("Jacob", year: 2);CreateNewStudent(name: "Andrew", studentid: 30, year: 2);CreateNewStudent("Vamshi", studentid: 4);CreateNewStudent(year: 2, name: "Hima", studentid: 4);Console.ReadLine();}
Console.WriteLine("Name = " + name + " : "+"StudentID = " + studentid + " : "+"Year = " + year); }static void Main(string[] args){
CreateNewStudent("Sukanya");CreateNewStudent("Prakash", 16); CreateNewStudent("Pinal", 40, 2);CreateNewStudent("Jacob", year: 2);CreateNewStudent(name: "Andrew", studentid: 30, year: 2);CreateNewStudent("Vamshi", studentid: 4);CreateNewStudent(year: 2, name: "Hima", studentid: 4);Console.ReadLine();}
Although Visual Studio’s IntelliSense doesn’t deal very well with
Dynamic, it works perfectly well for named and optional parameters.:
The demonstration code above produces the output seen in Figure 5's console window:
Limitations
As much as a I wish it were otherwise, Named and optional parameters
do not permit arguments to be omitted between commas. A Method signature
applies if all parameters are optional or have a corresponding argument
identified by name or position in the method call. As such, the
following calls are not accepted by the C-sharp Complier, because the
omitted optional arguments are being ignored:
CreateNewStudent("Hima", ,); // Not permitting arguments to be omitted between comas,
// although logically it should take default values for the other two parameters. CreateNewStudent(3,0); // Overload cannot convert string to integer. If the first
// parameter is string, it will automatically infer it as name.
// although logically it should take default values for the other two parameters. CreateNewStudent(3,0); // Overload cannot convert string to integer. If the first
// parameter is string, it will automatically infer it as name.
No comments:
Post a Comment