Remember that when we first learned ASP. NET, we were told that the page_load method can writeCode.
Therefore, we have written the page_load Method for a long time. Looking back, why is a common method,
Can be automatically called? The autoeventwireup attribute is known.
<% @ Page Language = "C #" autoeventwireup = "true" codefile = "default. aspx. cs" inherits = "default" %>
Generally, when we create a page, autoeventwireup is true. Msdn indicates whether the events of the control are automatically matched (autowire ).
If event auto-match is enabledTrueOtherwiseFalse. The default value isTrue.
Then we first come to the conclusion that when autoeventwireup is true, the method names such as page_load and page_init
Can be called automatically.
Next we will decompileSource codeLet's see what's going on. First, decompile the parent class of all pages: page class.
Public class page: templatecontrol, ihttphandler {}
After a rough look, no strings such as "page_load" are found, indicating that they are not processed in the page class. continue to search for the page class.
parent class templatecontrol class.
Public abstract class templatecontrol: control, inamingcontainer, ifilterresolutionservice {// fields private static object _ emptyeventsingleton; Private Static hashtable _ eventlistcache; Private Static idictionary _ eventobjects; Private Static object _ lockobject; private int _ maxresourceoffset; private inline _ values; private const string _ values = "ontransactionabort"; private const string _ ontransactioncommiteventname = "ontransactioncommit"; private const string _ values = "page_aborttransaction "; private const string _ partition = "page_committransaction"; private const string _ partition = "page_databind"; private const string _ partition = "page_error"; private const string _ pageinitcompleteeventname = "page_initcomplete "; private const string _ pageiniteventname = "page_init"; private const string _ pageloadcompleteeventname = "page_loadcomplete"; private const string _ pageloadeventname = "page_load"; private const string _ identifier = "page_preinit "; private const string _ pagepreloadeventname = "page_preload"; private const string _ response = "page_prerendercomplete"; private const string _ pageprerendereventname = "page_prerender"; private const string _ response = "response "; private const string _ pageunloadeventname = "page_unload ";
........}
Found! It's a black string. Continue to look up the portal and find the following method:
Code
Internal Void Hookupautomatichandlers ()
{
// Indicates whether automatic events are supported. The supportautoevents attribute is read-only and is true in all cases.
If ( This . Supportautoevents)
{
Object Obj2 = _ Eventlistcache [ Base . GetType ()];
Idictionary dictionary = Null ;
If (Obj2 = Null )
{
Lock (_ Lockobject)
{
Obj2 = _ Eventlistcache [ Base . GetType ()];
If (Obj2 = Null )
{
Dictionary = New Listdictionary ();
// Getdelegateinformation: add the matching method to the dictionary.
This . Getdelegateinformation (dictionary );
If (Dictionary. Count = 0 )
{
Obj2 = _ Emptyeventsingleton;
}
Else
{
Obj2 = Dictionary;
}
_ Eventlistcache [ Base . GetType ()] = Obj2;
}
}
}
// The methods similar to page_load found here are compared with the methods specified by the page. Load events.
// Add non-repeated events to the event
If (Obj2 ! = _ Emptyeventsingleton)
{
Dictionary = (Idictionary) obj2;
Foreach ( String Str In Dictionary. Keys)
{
Eventmethodinfo info = (Eventmethodinfo) dictionary [STR];
Bool Flag = False ;
Methodinfo = Info. methodinfo;
Delegate delegate2 = Base . Events [_ eventobjects [STR];
If (Delegate2 ! = Null )
{
Foreach (Delegate delegate3 In Delegate2.getinvocationlist ())
{
If (Delegate3.method. Equals (methodinfo ))
{
Flag = True ;
Break ;
}
}
}
If ( ! Flag)
{
Intptr functionpointer = Methodinfo. methodhandle. getfunctionpointer ();
Eventhandler Handler = New Callieventhandlerdelegateproxy ( This , Functionpointer, info. isargless). Handler;
Base . Events. addhandler (_ eventobjects [STR], Handler );
}
}
}
}
}
The above method is a piece of black pressure, summed up as 2 points: Find the page_load method on the page, add it to a dictionary,
Compare with the page. Load event to add non-repeated methods to the page. Load event. That is to say, if
There is a page_load method, and page. Load + = new eventhandler (page_load); add for page. Load
Then the page_load method is executed only once.
But who calls the hookupautomatichandlers () method? Where is the autoeventwireup attribute?
Used? I have not understood this yet. I guess it is in the ASP. NET page lifecycle that consists of modules before the page (such as httphandler
Or httpmodule) to determine the value of autoeventwireup. If it is true, the hookupautomatichandlers () method is called.
Reference:. Net (C #) internals: ASP. NET application and page Lifecycle
Next let's take a look at the templatecontrol. getdelegateinformation method.
Private void getdelegateinformation (idictionary dictionary) {If (httpruntime. isfulltrust) {This. Dictionary (dictionary);} else {This. getdelegateinformationwithassert (dictionary );}}
Further View
Private void getdelegateinformationwithassert (idictionary dictionary) {This. getdelegateinformationwithnoassert (dictionary );}
The key is the templatecontrol. getdelegateinformationwithnoassert method:
Private void getdelegateinformationwithnoassert (idictionary dictionary) {If (this is page) {This. getdelegateinformationfrow.hod ("page_preinit", dictionary); this. getdelegateinformationfrow.hod ("page_preload", dictionary); this. getdelegateinformationfrow.hod ("page_loadcomplete", dictionary); this. getdelegateinformationfrow.hod ("page_prerendercomplete", dictionary); this. getdelegateinformati Onfrow.hod ("page_initcomplete", dictionary); this. getdelegateinformationfrow.hod ("page_savestatecomplete", dictionary);} This. getdelegateinformationfrow.hod ("page_init", dictionary); this. getdelegateinformationfrow.hod ("page_load", dictionary); this. getdelegateinformationfrow.hod ("page_databind", dictionary); this. getdelegateinformationfrow.hod ("page_prerender", dictionary); this. getd Elegateinformationfrommethod ("page_unload", dictionary); this. getdelegateinformationfrommethod ("page_error", dictionary); If (! This. getdelegateinformationfrow.hod ("page_aborttransaction", dictionary) {This. getdelegateinformationfrommethod ("ontransactionabort", dictionary);} If (! This. getdelegateinformationfrow.hod ("page_committransaction", dictionary) {This. getdelegateinformationfrommethod ("ontransactioncommit", dictionary );}}
You can also see the familiar "page_load" string. Getdelegateinformationfrow.hod method name
It should be guessed that its function is to find the method with the specified name on the page:
Private bool handler (string methodname, idictionary dictionary) {eventhandler handler = (eventhandler) Delegate. createdelegate (typeof (eventhandler), this, methodname, true, false); If (handler! = NULL) {dictionary [methodname] = new eventmethodinfo (handler. method, false); Return true;} voidmethod method = (voidmethod) delegate. createdelegate (typeof (voidmethod), this, methodname, true, false); If (method! = NULL) {dictionary [methodname] = new eventmethodinfo (method. method, true); Return true;} return false ;}
The above code is used to search for a specified name in case-insensitive mode. If a parameter is found, it is added to the dictionary.
And then return. If no parameter is found, you can find the method of the specified name without the parameter and add it to the dictionary.
The method signature with parameters must be page_load (Object sender, eventargs E)
The method signature without parameters must be page_load ()
That is to say, page_load is case-insensitive and can be written as page_load. If there are parameters and no parameters, only those with parameters will be taken.
If no parameter is included, the system retrieves the parameter. If both the names include page_load and page_load
Is no parameter) method, then take the method written in the back (that is, who writes in the Code to the back ).
The execution time of page_load is after the onload method is executed by the control class (the parent class of the templatecontrol class.
The onload on the page is actually the onload method of the parent class, which is executed using polymorphism. In terms of efficiency, it is more efficient than page_load.
The method of loading events is high, so Microsoft's document (the address is forgotten) says: if efficiency is to be considered
Autoeventwireup is always set to false.
The following example demonstrates the conclusion: (autoeventwireup is set to true)
Example 1:
Public partial class default: Page {protected void page_load (Object sender, eventargs e) {response. write ("3");} protected void page_load (Object sender, eventargs e) {response. write ("2");} protected void page_load (Object sender, eventargs e) {response. write ("1 ");}}
Output 1, because the page_load method is case-insensitive,
The page_load method with multiple parameters takes only the last one.
Example 2:
Public partial class default: Page {protected void page_load (Object sender, eventargs e) {response. write ("1");} protected void page_load () {response. write ("2 ");}}
Output 1, because if there is a page_load with a parameter, no parameter is required.
Example 3:
Public partial class default: Page {protected void page_load (Object sender, eventargs e) {response. write ("1");} public default () {page. load + = new eventhandler (page_load );}}
Output 1, because the repeated method is not added to the load event Delegate chain
So it will only be executed once
Example 4:
Public partial class default: Page {protected void page_load (Object sender, eventargs e) {response. write ("1");} protected void page_load (Object sender, eventargs e) {response. write ("2");} public default () {page. load + = new eventhandler (page_load );}}
OUTPUT 12. Pay attention to the order of the methods in the delegate chain. The page_load method is first added to the constructor,
Then, find the method that matches the name of page_load and find page_load (because it is written later ),
Then, check whether there are duplicates and the search result is none. Therefore, add page_load to the delegate chain.
Example 5:
Public partial class default: Page {protected void page_load (Object sender, eventargs e) {response. write ("2");} protected override void onload (eventargs e) {response. write ("1"); base. onload (E); response. write ("3 ");}}
123 output. First, because of the onload of the override parent class, the onload method of the page is executed first,
Output 1, execute the onload method of the parent class, and push it up until the onload of the control class is executed.
Method, execute the load event's delegate chain method, execute the page_load method, and Output 2. Finally return
The onload method of the page outputs 3
Conclusion: When autoeventwireup is true, some execution rules in it are very strange, suchThe page_load method can be case-insensitive,
These are all discovered after decompilation, and no corresponding explanation can be found in msdn. If the page inherits the mybasepage class and the mybasepage class
Inherit from the page class. Both the page and mybasepage classes have the page_load method, which is more complex (for example, the page_load method of the mybasepage class ).
Without the virtual keyword, the running results may be different. This will affect the developer's logic and increase the development complexity. At the same time
The event mechanism is relatively inefficient. Therefore, we recommend that you set autoeventwireup to false and use only the override onload method, so that everything can be
Controlled by developers. (The above conclusions are the same for page_init () and other methods)