C #4.0 new features (1): Dynamic Lookup

Source: Internet
Author: User
Tags sapi

 


The main topic of C #4.0 is dynamic programming. Objects become more and more "dynamic", and their structures and behaviors cannot be captured through static types, or at least the compiler cannot know the structure and behavior of objects during program compilation. For example --

• A. Objects from dynamic programming languages such as Python or Ruby
• B. COM objects accessed through IDispatch
• C. General. NET types accessed through reflection
• D. Objects whose structures have changed-such as html dom objects
Dynamic search allows you to bypass the C # static type check when writing methods, operators, and indexers, accessing attributes and fields, and even calling objects, and parse them at runtime.
Dynamic search allows you to dynamically bind operations on an object to the object type at runtime, regardless of whether the object is reflected by COM, IronPython, html dom, or CLR. You can bypass the type check of the compiler in the program, and discard the type matching (lookup) to the runtime. If you need to operate such an object, a brand new type is used: dynamic.

The dynamic type)
C #4.0 introduces a new static type called dynamic. When you have a dynamic-type object, what you do to it will only be parsed at runtime --

1 dynamic d = GetDynamicObject (...);

2 d. M (7 );
C # The Compiler allows you to use any parameter to call a method on d because its type is dynamic. During running, the system checks the actual type of d and detects the meaning of "calling M with an int" on it.

It can be considered that the dynamic type is a special version of the object type, indicating that the object can be dynamically used. It is easy to choose whether to use dynamic behavior-any object can be implicitly converted to dynamic and "suspend Trust" until runtime. On the contrary, there is a "value assignment conversion" from dynamic to any other type, which can be implicitly converted in a structure similar to the value assignment --

1 dynamic d = 7; // implicit conversion

2 int I = d; // assignment conversion
Dynamic operations)
Not only method calls, field and attribute access, indexer and operator calls, but even delegate calls can be dynamically assigned --

1 dynamic d = GetDynamicObject (...);

2 d. M (7); // calling methods

3 d. f = d. P; // getting and settings fields and properties

4 d ["one"] = d ["two"]; // getting and setting thorugh indexers

5 int I = d + 3; // calling operators

6 string s = d (5, 7); // invoking as a delegate
01 class Program

02 {

03 static void Main (string [] args)

04 {

05 dynamic dyn = 1;

06 object obj = 1;

07

08 // Rest the mouse pointer over dyn and obj to see their

09 // types at compile time.

10 System. Console. WriteLine (dyn. GetType ());

11 System. Console. WriteLine (obj. GetType ());

12}

13}
Program output:

1 System. Int32

2

3 System. Int32
Dynamic keywords can also be used as type attributes, fields, indexers, parameters, return values, local variables, and type constraints. See the following example:

01 class ExampleClass

02 {

03 // A dynamic field.

04 static dynamic field;

05

06 // A dynamic property.

07 dynamic prop {get; set ;}

08

09 // A dynamic return type and a dynamic paramater type.

10 public dynamic exampleMethod (dynamic d)

11 {

12 // A dynamic local variable.

13 dynamic local = "Local variable ";

14 int two = 2;

15

16 if (d is int)

17 {

18 return local;

19}

20 else

21 {

22 return two;

23}

24}

25}
It can also be used as the target type in explicit type conversion, as follows:

01 static void convertToDynamic ()

02 {

03 dynamic d;

04 int I = 20;

05 d = (dynamic) I;

06 Console. WriteLine (d );

07

08 string s = "Example string .";

09 d = (dynamic) s;

10 Console. WriteLine (d );

11

12 DateTime dt = DateTime. Today;

13 d = (dynamic) dt;

14 Console. WriteLine (d );

15

16}

17 // Results:

18 // 20

19 // Example string.

20 // 2/17/2009 9:12:00 AM
It can also be used for the is, as, and typeof operators:

01 int I = 8;

02 dynamic d;

03 // With the is operator.

04 // The dynamic type behaves like object. The following

05 // expression returns true unless someVar has the value null.

06 if (someVar is dynamic ){}

07

08 // With the as operator.

09 d = I as dynamic;

10

11 // With typeof, as part of a constructed type.

12 Console. WriteLine (typeof (List <dynamic> ));

13

14 // The following statement causes a compiler error.

15 // Console. WriteLine (typeof (dynamic ));
Type conversion:

1 dynamic d1 = 7;

2 dynamic d2 = "a string ";

3 dynamic d3 = System. DateTime. Today;

4 dynamic d4 = System. Diagnostics. Process. GetProcesses ();
1 int I = d1;

2 string str = d2;

3 DateTime dt = d3;

4 System. Diagnostics. Process [] procs = d4;
Complete example:

01 using System;

02

03 namespace DynamicExamples

04 {

05 class Program

06 {

07 static void Main (string [] args)

08 {

09 ExampleClass ec = new ExampleClass ();

10 Console. WriteLine (ec. exampleMethod (10 ));

11 Console. WriteLine (ec. exampleMethod ("value "));

12

13 // The following line causes a compiler error because exampleMethod

14 // takes only one argument.

15 // Console. WriteLine (ec. exampleMethod (10, 4 ));

16

17 dynamic dynamic_ec = new ExampleClass ();

18 Console. WriteLine (dynamic_ec.exampleMethod (10 ));

19

20 // Because dynamic_ec is dynamic, the following call to exampleMethod

21 // with two arguments does not produce an error at compile time.

22 // However, itdoes cause a run-time error.

23 // Console. WriteLine (dynamic_ec.exampleMethod (10, 4 ));

24}

25}

26

27 class ExampleClass

28 {

29 static dynamic field;

30 dynamic prop {get; set ;}

31

32 public dynamic exampleMethod (dynamic d)

33 {

34 dynamic local = "Local variable ";

35 int two = 2;

36

37 if (d is int)

38 {

39 return local;

40}

41 else

42 {

43 return two;

44}

45}

46}

47}

48 // Results:

49 // Local variable

50 // 2

51 // Local variable
Runtime lookup)
During running, dynamic operations will be distributed according to the nature of the target object d --

COM Object (COM objects)
If d is a COM object, the operation uses COM IDispatch for dynamic allocation. This allows you to call the COM type that does not have the Primary interoperability Assembly (Primary Interop Assembly, PIA) and rely on the COM features that do not have the corresponding concepts in C #, such as index attributes and default attributes.

The following code dynamically obtains a COM object type, creates an instance of this COM object through this type, and is ready to call a method on this instance to implement the functions we need. This example references the SAPI. SpVoice object in the Speech API and calls its Speak () method.

Using System;

Type type = Type. GetTypeFromProgID ("SAPI. SpVoice ");
Dynamic spVoice = Activator. CreateInstance (type );
SpVoice. Speak ("Hello, C #4.0! "); Compile and run this example, we get the correct voice through the computer speaker.

Now let's start to think about a problem. The spVoice. Speak (string) function signature is actually unknown to the C # compiler during design and compilation. Because the spVoice variable type is System. _ ComObject, and because of SAPI. the ProgID corresponding to SpVoice points to an unmanaged COM object. In addition, we have not imported any TLB library. Therefore, the Speak () method can only be automatically bound by the compiler at runtime.

This is the most basic intent of dynamic search. It is proposed to simplify code in Office and COM interoperability programming. All runtime type information of dynamic variables is directly bound and executed by the runtime context (known as "late binding"). These tasks are completed through the System. Dynamic. RuntimeBinding class.

Dynamic objects)
If d implements the IDynamicObject interface, request d to perform the operation. Therefore, by implementing the IDynamicObject interface, the type can completely redefine the meaning of dynamic operations. This is widely used in dynamic languages such as IronPython and IronRuby to implement their dynamic object models. APIS also use such objects. For example, html dom allows you to directly use Attribute syntax to access object attributes.

Plain objects)
In addition, d is a standard. NET object, operations are distributed by reflection on its type, C # "runtime binder (runtime binder) "implements C # lookup and reload parsing during runtime. The essence behind it is to run the C # compiler as a runtime component to "complete" the dynamic operations delayed by the static compiler.

Consider the following code --

1 dynamic d1 = new Foo ();

2 dynamic d2 = new Bar ();

3 string s;

4

5 d1.M (s, d2, 3, null );
Since the receiver of M calls is of the dynamic type, the C # compiler will not try to parse the meaning of the call. Instead, it stores information about the call for running. This information (usually called "payload") is essentially equivalent --

"Use the following parameters to execute an instance method called M --

• 1. A string
• 2. A dynamic
• 3. an int face value of 3
• 4. the literal value of an object is null"
At runtime, assume that the actual type of d1 Foo is not the COM type, and IDynamicObject is not implemented. In this case, the C # runtime binder is responsible for heavy-load parsing. This is based on the runtime type information and is processed as follows --

• 1. Use reflection to obtain the actual runtime types of d1 and d2 objects. They do not have static types (including static type dynamic ). The result is that d1 is of the Foo type, while d2 is of the Bar type.
• 2. Use the common C # semantics to perform method searches and reload parsing on M (string, Bar, 3, null) calls on the Foo type.
• 3. If this method is found, call it; otherwise, a running exception is thrown.
Overload resolution with dynamic arguments)
1 // can be compiled or run

2 ec. exampleMethod2 ("a string ");

3

4 // the following code can be compiled, but an exception occurs during running.

5 ec. exampleMethod2 (d1 );

6 // the following code compilation will fail

7 // ec. exampleMethod2 (7 );
Even if the method call receiver is of the static type, the reload parsing still occurs at runtime. This happens when one or more real parameters are of the dynamic type --

1 Foo foo = new Foo ();

2 dynamic d = new Bar ();

3

4 var result = foo. M (d );
C # The runtime binder selects between the static known (statically known) loads of the M method on Foo Based on the d runtime type -- Bar. The result is of the dynamc type.

The Dynamic Language Runtime)
Dynamic Language Runtime (DLR) is an important component of the underlying Implementation of Dynamic search and is also an API added in. NET 4.0. DLR not only provides C # dynamic search, but also provides underlying infrastructure for the implementation of many other. NET Dynamic languages, such as IronPython and IronRuby. This general infrastructure ensures high interoperability, and more importantly, the DLR provides an excellent cache mechanism, greatly improving the efficiency of runtime dispatching.

For users who use C # dynamic search, in addition to higher performance, they do not feel the existence of DLR. However, if you want to implement your own dynamic object allocation, you can use the IDynamicObject interface to interoperate with DLR and insert your own behavior into it. This is a very advanced task and requires a deep understanding of the internal working principles of DLR. For API developers, it is worthwhile to spend some time on these issues so as to improve availability more broadly. For example, you can write a class library for a dynamic domain.

Known issues (Open issues)
• DLR allows you to create an object from an object that represents a class. However, the current implementation of C # does not have the syntax to support this function.
• Dynamic search cannot find extension methods. Regardless of whether the extension method depends on the Static Context of the Call (that is, the using statement appears), because the context information is not retained as part of the payload.
• Anonymous functions (lambda expressions) cannot be passed to dynamic method calls as real parameters. The compiler cannot bind (that is, "understand") an anonymous function without knowing the type to convert.
The result of these restrictions is that it is difficult to use the LINQ query on dynamic objects --

1 dynamic collection = ...;

2

3 var result = collection. Select (e => e + 5 );
If the Selected method is an extension method, dynamic search cannot find it. Even if it is an instance method, the above Code cannot be compiled, because lambda expressions cannot be passed as parameters to dynamic operations.

These restrictions are not planned to be addressed in C #4.0.

Note: dynamic is different from object. An object is a base class of any class. It is a strong CLR type and a reference type. It has complete runtime information. Any method signature or attribute that attempts to access an object that does not exist will be checked by the compiler during compilation and an error is reported. The dynamic type may be unknown during compilation. all calls to the dynamic type will not report errors during compilation. Only after DLR checks the information at runtime, to determine whether a call is successful or fails.

Thanks to these features of dynamic, it is widely used in COM and other interoperability programming. It simplifies and facilitates our code, but at the same time, because it has been opened, all strong types can be converted to dynamic, so if it is abused, it will greatly improve the difficulty of code maintenance. This is because the compiler cannot check more errors during compilation. Therefore, we strongly recommend that you do not abuse dynamic in other places except for the interoperability to avoid potential maintenance costs for existing code.

 


 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.