C # Dynamic keywords: Why dynamic is faster than reflection

Source: Internet
Author: User

The Main method is as follows:

Copy codeThe Code is as follows: static void Main (string [] args)
{
Dynamic str = "abcd ";
Console. WriteLine (str. Length );

Console. WriteLine ();
Console. WriteLine (str. Substring (1 ));

Console. ReadLine ();
}

The result is as follows:

When recycltor is used for decompilation, you can see that:

The complete code is as follows:

Copy codeThe Code is as follows: private static void Main (string [] args)
{
Object obj1 = "abcd ";
If (Program. <Main> o _ SiteContainer0. <> p _ Site1 = null)
{
Program. <Main> o _ SiteContainer0. <> p _ Site1 = CallSite <Action <CallSite, Type, object>. create (Binder. invokeMember (CSharpBinderFlags. resultDiscarded, "WriteLine", null, typeof (Program), new CSharpArgumentInfo [] {CSharpArgumentInfo. create (CSharpArgumentInfoFlags. isStaticType | CSharpArgumentInfoFlags. useCompileTimeType, null), CSharpArgumentInfo. create (CSharpArgumentInfoFlags. none, null )}));
}
If (Program. <Main> o _ SiteContainer0. <> p _ Site2 = null)
{
Program. <Main> o _ SiteContainer0. <> p _ Site2 = CallSite <Func <CallSite, object, object>. create (Binder. getMember (CSharpBinderFlags. none, "Length", typeof (Program), new CSharpArgumentInfo [] {CSharpArgumentInfo. create (CSharpArgumentInfoFlags. none, null )}));
}
Program. <Main> o _ SiteContainer0. <> p _ Site1.Target (Program. <Main> o _ SiteContainer0. <> p _ Site1, typeof (Console), Program. <Main> o _ SiteContainer0. <> p _ Site2.Target (Program. <Main> o _ SiteContainer0. <> p _ Site2, obj1 ));
Console. WriteLine ();
If (Program. <Main> o _ SiteContainer0. <> p _ Site3 = null)
{
Program. <Main> o _ SiteContainer0. <> p _ Site3 = CallSite <Action <CallSite, Type, object>. create (Binder. invokeMember (CSharpBinderFlags. resultDiscarded, "WriteLine", null, typeof (Program), new CSharpArgumentInfo [] {CSharpArgumentInfo. create (CSharpArgumentInfoFlags. isStaticType | CSharpArgumentInfoFlags. useCompileTimeType, null), CSharpArgumentInfo. create (CSharpArgumentInfoFlags. none, null )}));
}
If (Program. <Main> o _ SiteContainer0. <> p _ Site4 = null)
{
Program. <Main> o _ SiteContainer0. <> p _ Site4 = CallSite <Func <CallSite, object, int, object>. create (Binder. invokeMember (CSharpBinderFlags. none, "Substring", null, typeof (Program), new CSharpArgumentInfo [] {CSharpArgumentInfo. create (CSharpArgumentInfoFlags. none, null), CSharpArgumentInfo. create (CSharpArgumentInfoFlags. constant | CSharpArgumentInfoFlags. useCompileTimeType, null )}));
}
Program. <Main> o _ SiteContainer0. <> p _ Site3.Target (Program. <Main> o _ SiteContainer0. <> p _ Site3, typeof (Console), Program. <Main> o _ SiteContainer0. <> p _ Site4.Target (Program. <Main> o _ SiteContainer0. <> p _ Site4, obj1, 1 ));
Console. ReadLine ();
}

First, the compiler automatically generates a static class:Copy codeThe Code is as follows: [CompilerGenerated]
Private static class <Main> o _ SiteContainer0
{
// Fields
Public static CallSite <Action <CallSite, Type, object >><> p _ Site1;
Public static CallSite <Func <CallSite, object, object >><> p _ Site2;
Public static CallSite <Action <CallSite, Type, object >><> p _ Site3;
Public static CallSite <Func <CallSite, object, int, object >><> p _ Site4;
}

Why are there four CallSite <T> objects? In our code

Console. WriteLine (str. Length );
Console. WriteLine ();
Console. WriteLine (str. Substring (1 ));
A total of four dynamic objects are used. 1: Console. writeLine (dynamic); str. length returns dynamic2: dynamic. length; 3: Console. writeLine (dynamic); str. substring returns dynamic4: dynamic. substring (1); 1, 2, 3, 4, respectively, corresponding to <> p_Site1, 2, 3, 4;

Because 1 and 3 have no returned values, Action and 2 and 4 both have returned values. Therefore, they are Func. the code above may not be clear. Let's manually generate the code: Create a class SiteContainer to replace the class automatically generated by the compiler.

Copy codeThe Code is as follows: [CompilerGenerated]
Public static class SiteContainer
{
// Fields
Public static CallSite <Action <CallSite, Type, object> p _ Site1;
Public static CallSite <Func <CallSite, object, object> p _ Site2;
Public static CallSite <Action <CallSite, Type, object> p _ Site3;
Public static CallSite <Func <CallSite, object, int, object> p _ Site4;
}

Next, let's take a look at the method for initializing p _ Site1:Copy codeThe Code is as follows: if (SiteContainer. p _ Site1 = null)
{
CallSiteBinder csb = Microsoft. CSharp. RuntimeBinder. Binder. InvokeMember (
CSharpBinderFlags. ResultDiscarded,
"WriteLine", null, typeof (Program ),
New CSharpArgumentInfo []
{
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. IsStaticType | CSharpArgumentInfoFlags. UseCompileTimeType, null ),
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. None, null)
});
SiteContainer. p _ Site1 = CallSite <Action <CallSite, Type, object>. Create (csb );
}

InvokeMember method Signature: public static CallSiteBinder InvokeMember (CSharpBinderFlags flags, string name, IEnumerable <Type> typeArguments, Type context, IEnumerable <CSharpArgumentInfo> argumentInfo); 1: here, CSharpBinderFlags transmits ResultDiscarded, which indicates that the result is discarded. Therefore, it can be bound to a void return method. 2: The name is "WriteLine" and the name of the method to be called. 3: List of typeArguments. type parameters. null is passed. 4: context: the System. Type used to indicate the position of this operation. Here is the Program5: argumentInfo: parameter information. Let's take a look at how p _ Site2 initializes it:Copy codeThe Code is as follows: if (SiteContainer. p _ Site2 = null)
{
CallSiteBinder csb = Microsoft. CSharp. RuntimeBinder. Binder. GetMember (
CSharpBinderFlags. None, "Length", typeof (Program ),
New CSharpArgumentInfo []
{
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. None, null)
});

SiteContainer. p _ Site2 = CallSite <Func <CallSite, object, object>. Create (csb );
}

As you can see, unlike p _ Site1, The GetMember method is called.
 
Since there are two CallSite <T> objects, how are they called ??
Call CallSite <T>. Target.
 
 
 
// This is the code generated by the compiler: // SiteContainer. p _ Site1.Target (SiteContainer. p _ Site1, typeof (Console), // SiteContainer. p _ Site2.Target (SiteContainer. p _ Site2, obj1) //); var pSite2Result = SiteContainer. p _ Site2.Target (SiteContainer. p _ Site2, obj1); SiteContainer. p _ Site1.Target (SiteContainer. p _ Site1, typeof (Console), pSite2Result );

 
Let's see how to call it:
Because SiteContainer. p _ Site2, The Length attribute is called.
Call the target method of p _ Site2 and execute p _ Site2. The object is obj1.
Dlr calls obj1.Length and returns the result. Therefore, pSite2Result = 4;
Next, call the target of p _ Site1 to call the WriteLine method of the Console class. The parameter is pSite2Result. Therefore, output 4.
 
Finally, let's take a look at how dynamic calls the Substring method:

The Substring method corresponds to p _ Site4. Because the Substring method passes parameter 1 and has a return value

The p _ Site4 object is:

Public static CallSite <Func <CallSite, object, int, object> p _ Site4;
Initialization:

Copy codeThe Code is as follows: if (SiteContainer. p _ Site4 = null)
{
CallSiteBinder csb = Microsoft. CSharp. RuntimeBinder. Binder. InvokeMember (
CSharpBinderFlags. None, "Substring", null, typeof (Program ),
New CSharpArgumentInfo []
{
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. None, null ),
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. Constant
| CSharpArgumentInfoFlags. UseCompileTimeType, null)
});
SiteContainer. p _ Site4 = CallSite <Func <CallSite, object, int, object>. Create (csb );
}

Basically, it is similar to the above p _ Site1, but the parameter information is: CSharpArgumentInfoFlags. Constant \

Because Substring (1) is called, 1 is passed during compilation, and 1 is a constant. The call is as follows:

Copy codeThe Code is as follows: var subStringResult = SiteContainer. p _ Site4.Target (SiteContainer. p _ Site4, obj1, 1 );
SiteContainer. p _ Site1.Target (SiteContainer. p _ Site1, typeof (Console), subStringResult );

The same is explained above.

The complete Main Function Code is as follows:

Copy codeThe Code is as follows: static void Main (string [] args)
{
Object obj1 = "abcd ";

If (SiteContainer. p _ Site1 = null)
{
CallSiteBinder csb = Microsoft. CSharp. RuntimeBinder. Binder. InvokeMember (
CSharpBinderFlags. ResultDiscarded,
"WriteLine", null, typeof (Program ),
New CSharpArgumentInfo []
{
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. IsStaticType | CSharpArgumentInfoFlags. UseCompileTimeType, null ),
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. None, null)
});
SiteContainer. p _ Site1 = CallSite <Action <CallSite, Type, object>. Create (csb );
}

If (SiteContainer. p _ Site2 = null)
{
CallSiteBinder csb = Microsoft. CSharp. RuntimeBinder. Binder. GetMember (
CSharpBinderFlags. None, "Length", typeof (Program ),
New CSharpArgumentInfo []
{
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. None, null)
});

SiteContainer. p _ Site2 = CallSite <Func <CallSite, object, object>. Create (csb );
}

If (SiteContainer. p _ Site4 = null)
{
CallSiteBinder csb = Microsoft. CSharp. RuntimeBinder. Binder. InvokeMember (
CSharpBinderFlags. None, "Substring", null, typeof (Program ),
New CSharpArgumentInfo []
{
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. None, null ),
CSharpArgumentInfo. Create (CSharpArgumentInfoFlags. Constant | CSharpArgumentInfoFlags. UseCompileTimeType, null)
});
SiteContainer. p _ Site4 = CallSite <Func <CallSite, object, int, object>. Create (csb );
}

Var lengthResult = SiteContainer. p _ Site2.Target (SiteContainer. p _ Site2, obj1 );
SiteContainer. p _ Site1.Target (SiteContainer. p _ Site1, typeof (Console), lengthResult );

Var subStringResult = SiteContainer. p _ Site4.Target (SiteContainer. p _ Site4, obj1, 1 );
SiteContainer. p _ Site1.Target (SiteContainer. p _ Site1, typeof (Console), subStringResult );

Console. ReadLine ();
}

Here, I didn't use p _ Site3, because p _ Site3 is the same as p _ Site1, but why does Microsoft generate four CallSite <T> objects, because 1 and 3 are exactly the same, is it for simplicity ?? Fortunately, there is a delay in Initialization. Otherwise, there are so many static fields that I don't know what impact it will have on the system,
The result is as follows:

You can also know from this exampleWhy is dynamic faster than reflection.
1: if (p _ Site1) = null, p _ Site1 = xxx, and p _ Site1 is a static field in the static class, so it has cache effect.
2: CallSite <T>. Target: Level 0 cache-dedicated Delegation Based on site history records.
Calling with delegation is naturally faster than reflection.

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.