Dynamic Enhancements The new dynamic functionality in .NET 4.0 allows us to work with types not known at compile time in an intuitive and easy to read way.. Static Languages In a stati
Trang 1Further Reading
Variance is a difficult subject, so for more information please refer to the following blogs and book:
•
http://blogs.msdn.com/charlie/archive/2008/10/28/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx
• http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/
default.aspx
• Skeet, Jon (2008) C# in depth Manning Publications
Dynamic Enhancements
The new dynamic functionality in NET 4.0 allows us to work with types not known at compile time in an intuitive and easy to read way Many of you may be wondering what can the dynamic changes do for
you The dynamic changes allow us to do the following:
• Write more readable code with fewer casting operations
• Create new languages to utilize the NET Framework, such as IronPython and
IronRuby Additionally, NET’s dynamic architecture allows these languages to
automatically benefit from future framework advances.Utilize other dynamic
languages and their libraries
• Utilize other dynamic languages and their libraries from C# and VB.NET
• Introduce customization/scripting and debugging/querying functionality within
our applications
• Work with COM objects more easily Microsoft Office COM is going to be around
for some time whether you like it or not
• Many other cool uses we haven’t thought of yet
Can’t We Do This Kind of Thing Already in NET?
.NET has a number of classes and methods for working with types not known at compile time, such as
reflection and expression trees However, if you have spent much time with these technologies, you will known that they can make for some clunky and difficult to read code As I will show you, the dynamic
enhancements can make your life much easier
Before we look at how to use the dynamic enhancements, we need to understand the difference
between statically and dynamically typed languages
Static Languages
In a statically typed language, such as C# or C, the compiler checks you are using types correctly at
compile time Compilation will fail, for example, if you assign a string to an integer or misspell a variable name Statically typed languages can catch simple syntax errors and typos during development and as the compiler knows the types it will be working with static languages generally run quicker then dynamic languages (next) as optimizations can be performed on code
Trang 2Dynamic Languages
In contrast, dynamic languages, such as JavaScript, Python, Lisp, and Ruby, do not perform type checks
on code until runtime This can be a big advantage if you don’t know the type of object you will be working with at compile time These features can also make it possible to perform some interesting code tricks and reduce tedious casting operations if the language can work out how to use the type Some developers feel dynamic languages can help them develop and prototype applications much quicker, and can be particularly suitable for testing and prototyping applications
The main disadvantage of working with dynamic languages is they of course lack compile time checks and generally have inferior performance when compared to static languages When working with dynamic languages, simple syntax errors and typos can stop your code working I think anyone that has done any web development has spent much time tracking down such an error in JavaScript with its very helpful “object not set to an instance” message
Dynamic Dangers
When working with dynamic types and the Dynamic Language Runtime (DLR) there are three
considerations you should bear in mind
• IDE support is limited
• Generally, performance is poor (although precompilation is sometimes possible),
especially on the first call to a method where the DLR has not yet cached a method call
• Using the DLR unnecessarily is not big or clever (more complexity = bad)
I’ll cover the DLR in detail later in this chapter
Type Dynamic
.NET 4.0 introduces a new type dynamic that allows you to tell the compiler to resolve a variable’s type at runtime Somewhat paradoxically the keyword dynamic statically types an object as dynamic
To declare an object as dynamic, prefix the variable name with the type dynamic:
dynamic myDynamic="Something";
Console.WriteLine(myDynamic.GetType().Name);
Console.ReadKey();
What type will be output on the second line? Dynamic, object?
For those of you who said String you are correct (now stop looking so smug); I will explain why this
is shortly
Is dynamic the Same as Var?
No, dynamic is very different When the var keyword is used the compiler infers the type of value you are using and writes the appropriate code for you when you compile the application Variables declared using var benefit from type checks, Intellisense, and offer better performance than their dynamic equivalent Types declared as dynamic are evaluated at run time and do not have these benefits
Trang 3Why Type Variables as Dynamic?
One advantage is that it can avoid some tedious casting and Reflection code For example, let’s say we
want to create an instance of a type using a string and call a method on it at runtime In our example we will create a StringBuilder instance and call the Append method on it using Reflection:
object UsingReflection =
Activator.CreateInstance(Type.GetType("System.Text.StringBuilder"));
Type ObjectType = UsingReflection.GetType();
//Append has many overloads so we need to tell reflection which type we will use
Type[] TypeArray = new Type[1];
TypeArray.SetValue(typeof(string), 0);
var ObjectMethodInfo=ObjectType.GetMethod("Append", TypeArray);
ObjectMethodInfo.Invoke(UsingReflection, new object[] { "alex" });
Console.WriteLine(
ObjectType.GetMethod("ToString", new Type[0]).Invoke(UsingReflection, null)
);
Console.ReadKey();
By using dynamic, however, we can make this simpler and more readable (and I know which bit of
code I could remember):
dynamic usingDynamic = Activator.CreateInstance(Type.GetType("System.Text.StringBuilder"));
usingDynamic.Append("Hello");
Console.WriteLine(UsingDynamic.ToString());
Console.ReadKey();
NOTE Technically you could do something similar in VB.NET by declaring UsingDynamic as object, so arguably VB.NET could be considered to contain dynamic functionality already
Consider using dynamic types in the following situations:
• When working with COM, dynamic types allow a more concise syntax (we saw this
earlier) Let the DLR do the work figuring out how to bind your method and
property calls
• When interacting with a dynamic language such as IronPython
• When working with objects that have changing structures, such as HTML or XML
documents (we will look at this shortly)
System.Dynamic.ExpandoObject
ExpandoObject is a strange new beast in the NET Framework that allows you to add and remove
properties, methods, and events at runtime The following example demonstrates how to add two new values and a method:
Trang 4using System.Dynamic
dynamic MyExpando = new ExpandoObject();
MyExpando.Value1 = "new value 1";
MyExpando.Value2 = "new value 2";
MyExpando.DoSomething = new Action(() => Console.WriteLine("DoSomething called"));
Console.WriteLine(MyExpando.Value1);
MyExpando.DoSomething();
Console.ReadKey();
ExpandoObject could be used for wrapping data and making it easier to work with and is included for interoperability with dynamic languages that support this concept
System.Dynamic.DynamicObject
.NET 4.0 introduces a new class called DynamicObject that allows the definition of runtime behavior, offering a much greater level of control than ExpandoObject It is important to note that DynamicObject is never instantiated directly but must be inherited from
DynamicObject again is great for wrapping data and making it easier to work with, but offers a much finer level of control than ExpandoObject If you just need to define parameters at runtime you will probably be adequately served by ExpandoObject (above) however DynamicObject allows you full control over various operations performed
The following example shows how to query an XML document using properties to create more readable code:
using System.Dynamic;
using System.Xml.Linq;
class Program
{
static void Main(string[] args)
{
dynamic easierXML =
new EasierXML(@"<test><node1>Alpha</node1><node2>Beta</node2></test>");
Console.WriteLine(easierXML.node1);
Console.WriteLine(easierXML.node2);
Console.ReadKey();
}
public class EasierXML : DynamicObject
{
private XDocument _xml = new XDocument();
public EasierXML(string Xml)
{
this._xml = XDocument.Parse(Xml);
}
Trang 5public override bool TryGetMember(GetMemberBinder binder,
out object result)
{
string nodeName = binder.Name;
result = _xml.Element("test").Element(nodeName).Value;
return true;
}
}
}
In this example, the TryGetMember() method intercepts the call to node1 and node2, thus allowing
us to query the XML document and return the individual nodes
IDynamicMetaObjectProvider
IDynamicMetaObjectProvider is an important interface in the dynamic world that represents an object that has operations bound at runtime Both ExpandoObject and DynamicObject implement this interface You
can use this interface to add dynamic functionality to your own classes IDynamicMetaObjectProvider
requires you to implement GetMetaObject(),(), which resolves binding operations (for example, method or property invocation on your object)
Dynamic Limitations
When working with dynamic objects, there are a number of constraints you should be aware of:
• All methods and properties in classes have to be declared public to be dynamically
accessible
• You cannot use the DLR to create classes in C# or VB.NET Apparently, the DLR
does allow you to create classes, but this cannot be expressed using C# or VB.NET
• Dynamic objects cannot be passed as arguments to other functions
• Extension methods cannot be called on a dynamic object and a dynamic object
cannot be passed into extension objects
Annoyingly, these restrictions stop you calling an extension method on a dynamic object
Dynamic IL
You may be wondering what code the C# compiler generates when you use the dynamic keyword Let’s
take a look at the IL that is generated using ILDASM for a simple console application that declares and
initializes a string:
string d;
d = "What do I look like in IL";