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.