Lập trình .net 4.0 và visual studio 2010 part 8 doc

6 331 0
Lập trình .net 4.0 và visual studio 2010 part 8 doc

Đang tải... (xem toàn văn)

Thông tin tài liệu

CHAPTER 3  LANGUAGE AND DYNAMIC CHANGES 55 public 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"; CHAPTER 3  LANGUAGE AND DYNAMIC CHANGES 56 This will generate the following IL: .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 8 (0x8) .maxstack 1 .locals init ([0] string d) IL_0000: nop IL_0001: ldstr "What do I look like in IL" IL_0006: stloc.0 IL_0007: ret } // end of method Program::Main Now we will alter d to be of type dynamic: dynamic d; d = ”What do I look like in IL?”; This will generate the following IL: .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 8 (0x8) .maxstack 1 .locals init ([0] object d) IL_0000: nop IL_0001: ldstr "What do I look like in IL" IL_0006: stloc.0 IL_0007: ret } // end of method Program::Main Note how the line locals init ([0] object d) replaces locals init ([0] string d) in the dynamic example. This is probably what you might expect to happen, but let’s take another more complex example. Create a new console application called Chapter3.DynamicComplex and add the following code: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Chapter3.DynamicComplex { class Program { static void Main(string[] args) { TestClass t = new TestClass(); t.Method1(); } } CHAPTER 3  LANGUAGE AND DYNAMIC CHANGES 57 public class TestClass { public void Method1() { } } } Compile the application and examine the IL using ILDASM. You will find something similar to the following: .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 15 (0xf) .maxstack 1 .locals init ([0] class Chapter3.DynamicComplex.TestClass t) IL_0000: nop IL_0001: newobj instance void Chapter3.DynamicComplex.TestClass::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: callvirt instance void Chapter3.DynamicComplex.TestClass::Method1() IL_000d: nop IL_000e: ret } // end of method Program::Main However, if we alter our t variable to the following: dynamic t = new TestClass(); t.Method1(); then the IL will look very different (I have removed some of the IL to save some trees): class [mscorlib]System.Collections.Generic.IEnumerable`1<class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>) IL_003a: call class [System.Core] System.Runtime.CompilerServices.CallSite`1<!0> class [System.Core]System.Runtime.CompilerServices.CallSite`1 <class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite,object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) IL_003f: stsfld class [System.Core]System.Runtime.CompilerServices .CallSite`1<class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite,object>> Chapter3.DynamicComplex.Program/'<Main>o__SiteContainer0'::'<>p__Site1' IL_0056: callvirt instance void class [mscorlib]System.Action`2<class [System.Core]System.Runtime.CompilerServices.CallSite,object>::Invoke(!0, !1) Whoa, what is happening here? Well the short answer is that calls to dynamic methods are sent to the Dynamic Language Runtime for resolution. It is time to take a look into how the DLR works. CHAPTER 3  LANGUAGE AND DYNAMIC CHANGES 58 Dynamic Language Runtime (DLR) The Dynamic Language Runtime (DLR) is behind all the cool dynamic functionality and sits just above the core .NET framework. The DLR’s job is basically to resolve calls to dynamic objects, cache dynamic calls making them as quick as possible, and enable interaction between languages by using a common format. The DLR has actually been around a while, and was included in earlier versions of Silverlight. You can even view the source code behind the DLR at: http://dlr.codeplex.com. Note that this version contains a number of features not present in the framework version. When discussing the DLR we need to understand five main concepts: • Expression trees/Abstract Syntax Trees (AST) • Dynamic Dispatch • Binders • IDynamicObject • Call Site Caching Expression/Abstract Syntax Trees (AST) Expression trees are a way of representing code in a tree structure (if you have done any work with LINQ, you may have come across this before with the Expression class). All languages that work with the DLR represent code in the same structure allowing interoperability. Dynamic Dispatch Dynamic Dispatch is the air traffic control center of the DLR, and is responsible for working out what to do with dynamic objects and operations and sending them to the appropriate binder that takes care of the details. Binders Binders resolve classes from dynamic dispatch. .NET 4.0 currently supports the following binder types: • Object Binder .NET (uses Reflection and resolved our earlier example to type string) • JavaScript binder (IDynamicObject) • IronPython binder (IDynamicObject) • IronRuby binder (IDynamicObject) • COM binder (IDispatch) Note that dynamic objects can resolve calls themselves without the DLR’s assistance (if they implement IDynamicObject), and this method will always be used first over the DLR’s dynamic dispatch mechanism. CHAPTER 3  LANGUAGE AND DYNAMIC CHANGES 59 IDynamicObject Sometimes you will want objects to carry out resolution themselves, and it is for this purpose the IDynamicObject exists. Normally dynamic objects are processed according to type, but if they implement the IDynamicObject interface then the object will resolve calls itself. IDynamicObject is used in IronRuby and IronPython. Callsite Caching Resolving objects is an expensive operation, so the DLR caches dynamic operations. When a dynamic function or operation is performed, the DLR checks to see if it has been called already (Level 0 cache). If it hasn’t, then the 10 most recently used dynamic methods for this callsite will be checked (Level 1 cache). A cache is also maintained across all target sites with the same binder object (Level 2 cache). IronPython A similar process to this is used when languages such as IronPython interact with .NET. What follows is a high-level version of how the DLR processes an IronPython file: 1. The IronPython file is first compiled into intermediary IronPython AST. (Not all languages will necessarily create an intermediary AST, but IronPython’s developers decided this would be a useful step for creating language-specific tools.) 2. The IronPython AST is then mapped to the generic DLR specific AST. 3. The DLR then works with the generic AST. For a detailed look at how this works with Iron Python please refer to: http://msdn.microsoft.com/ en-us/magazine/cc163344.aspx. As all languages end up being compiled into the same common AST structure, it is then possible for interaction between them. Embedding Dynamic Languages One use of dynamic languages that really excites me is the ability to embed them within your C# and VB.NET applications. One possible use would be to use them to define complex business rules and logic. Dynamic languages are often utilized in computer game construction to script scenarios and logic (such as how Civilization IV utilizes Python). Let’s take a look at how to work with IronPython in a C# application. Calling IronPython from .NET The following example passes a value into a simple IronPython script from C#. Note that you should have installed IronPython from http://ironpython.codeplex.com/. Now add a reference to IronPython.dll and Microsoft.Scripting.dll (at the time of writing these don’t show up on the main Add Reference window but are located at C:\Program Files (x86)\IronPython 2.6). CHAPTER 3  LANGUAGE AND DYNAMIC CHANGES 60 using Microsoft.Scripting; using Microsoft.Scripting.Hosting; using IronPython.Hosting; namespace Chapter3.PythonExample { class Program { static void Main(string[] args) { ScriptEngine pythonEngine = Python.CreateEngine(); ScriptScope scope = pythonEngine.CreateScope(); string script = @"print ""Hello "" + message"; scope.SetVariable("message", "world!"); ScriptSource source = scope.Engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements); source.Execute(scope); Console.ReadKey(); } } } IronPython is already in use in two real-world applications, so let’s take a look at these now. Red Gate Reflector Add-In Many of you will be familiar with the tool Reflector (www.red-gate.com/products/reflector/). Reflector allows you to explore an assembly and view the IL code within it. C# MVP Ben Hall developed an add-in (Methodist) to Reflector that allows you to actually call the classes and methods within the type you are exploring using Iron Python. For more information please consult: http://mail.simple-talk.com/ dotnet/.net-tools/methodist-make net-reflector-come-alive-with-ironpython/. ResolverOne One of the best know uses of IronPython is for ResolverOne (http://www.resolversystems.com). ResolverOne is an application that allows you to work with Excel’s objects using IronPython. See Figure 3-3. . .entrypoint // Code size 8 (0x8) .maxstack 1 .locals init ( [0] string d) IL _00 00: nop IL _00 01: ldstr "What do I look like in IL" IL _00 06: stloc .0 IL _00 07: ret } // end of method. .entrypoint // Code size 8 (0x8) .maxstack 1 .locals init ( [0] object d) IL _00 00: nop IL _00 01: ldstr "What do I look like in IL" IL _00 06: stloc .0 IL _00 07: ret } // end of method. Chapter3.DynamicComplex.TestClass::.ctor() IL _00 06: stloc .0 IL _00 07: ldloc .0 IL _00 08: callvirt instance void Chapter3.DynamicComplex.TestClass::Method1() IL _00 0d: nop IL _00 0e: ret } // end of method Program::Main

Ngày đăng: 01/07/2014, 21:20

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan