卷積神經網路相關(1):卷積神經網路模型的引數量Params和計算量FLOPs簡單程式碼
轉載:https://www.cnblogs.com/edisonchou/archive/2012/03/20/2407675.html
今天跟隨視訊學習了一下C#中最重要的一些概念之委託與事件。老楊的視訊講的還是挺深入淺出,不過剛接觸C#.NET的人還是朦朦朧朧,就像張子陽先生說的“每次見到委託和事件就覺得心裡別(biè)得慌,混身不自在”。跨過這道坎的人就有種一覽眾山小的感覺了。我又瀏覽了皺華棟老師JamesZou的博文《深入理解C#委託及原理》(地址:http://www.cnblogs.com/jameszou/archive/2011/07/21/2112497.html),以及張子陽Jimmy Zhang的博文《C# 中的委託和事件》(地址:
1.委託是神馬?
用最通俗易懂的話來講,你就可以把委託看成是用來執行方法(函式)的一個“指標”。用鄒老師的一個舉例:“設想,如果我們寫了一個廚師做菜方法用來做菜,裡面有拿菜、切菜、配菜、炒菜 四個環節,但編寫此方法程式碼的人想讓配菜這個環節讓呼叫方法的人實現,換句話說,就是想在方法被呼叫時接收程式碼 作為引數,在方法中執行這端傳進來的程式碼。但,怎麼為一個方法傳 程式碼 進來呢?當然大家想到了傳遞介面方式來實現,咱先不討論介面,因為微軟為我們提供了一個叫做委託的型別。”
現在來看看怎樣使用委託,根據itcast的ppt內容:
宣告委託的方式:delegate 返回值型別 委託型別名(引數) 比如delegate void StringProcess(string s); 注意這裡的除了前面的delegate,剩下部分和宣告一個函式一樣,但是StringProcess不是函式名,而是委託型別名
宣告的委託是一種型別,就像int、Person一樣,如果要用的話還要宣告委託型別的變數,宣告委託型別變數的方式:StringProcess f1;
將委託型別變數指向函式 StringProcess sp = new StringProcess(SayHello),這樣就可以像呼叫普通函式一樣把sp當成函式用了。委託可以看做是函式的指標。整數可以用整數變數指向它,物件可以用物件變數指向它,函式也可以用委託變數指向它。和直接呼叫函式的區別:用委託就可以指向任意的函式,哪怕是之前沒定義的都可以,而不使用受限於那幾種。
將委託型別變數指向函式還可以簡化成StringProcess sp = SayHello,編譯器幫我們進行了new。但是不能sp=PrintIt(),因為這樣就成了“執行PrintIt函式,並且將sp指向PrintIt的返回值”。
這裡看一個數據過濾的例子,輸出int陣列中的正整數:
1.宣告一個委託:delegate bool FilterDelegate(int i);
2.封裝一個過濾的靜態方法,引數中包含一個過濾器的方法委託,返回泛型List<int>列表:
static List<int> Filter(List<int> list,FilterDelegate fd)
{
List<int> listTest = new List<int>();
foreach(int i in list)
{
if(fd(i))
{
listTest.Add(i);
}
}
return listTest;
}
3.寫一個判斷是否為正整數的方法,返回值為bool型別:
static bool isZhengshu(int i)
{
return i > 0;
}
4.在main函式中宣告一個List列表,然後新增部分測試資料,將委託指向判斷正整數的方法,最後遍歷輸出過濾後的陣列資料;
List<int> listOne = new List<int>();
listOne.Add(1);
listOne.Add(-4);
listOne.Add(8);
listOne.Add(-6);
listOne.Add(13);
FilterDelegate fd = isZhengshu;
List<int> listResult = Filter(listOne, isZhengshu);
foreach (int i in listResult)
{
Console.WriteLine(i);
}
執行後,顯示:1 8 13
通過一個小例子,可以得出一個小結論:C# 中的委託類似於 C 或 C++ 中的函式指標。使用委託使程式設計師可以將方法引用封裝在委託物件內。然後呼叫該委託物件就可以執行委託物件內方法引用指向的方法,而不必在編譯時知道將呼叫哪個方法(如引數為委託型別的方法,也就是提供了為程式回撥指定方法的機制)。”摘錄自MSDN;
鄒老師的通俗說法是:“就是一個能存放很多方法的指標的呼叫清單(但方法簽名必須和委託型別簽名一樣),你一呼叫這個清單,那麼清單裡的所有的指標所對應的方法就會依次被執行。”
而委託的原理是神馬?這裡就需要跟隨鄒老師的博文走走了,通過VS中自帶的MSIL反編譯程式,將生成後的.exe拖到工具中檢視委託型別宣告的程式碼,發現其編譯前就生成了一個類;它繼承了System.MulticastDelegate,包含了構造方法、BeginInvoke、EndInvoke、Invoke方法。另外MulticastDelegate則繼承自Delegate類。通過Reflector反編譯工具,可以看出:繼承關係:編譯前生成的類 –> MulticastDelegate–> Delegate,而MulticastDelegate類中有3個重要的成員,其中兩個繼承自 Delegate:
這三者的作用分別是:
_methodPtr 裡儲存的就是 方法指標。
_target 裡用來儲存方法所在的物件。
_invocationList 其實使用時是個object陣列,在註冊多個方法時,其他方法就儲存在此成員中,而它也就是 委託鏈 的關鍵容器。--摘自鄒老師的博文;
2.事件閃亮出場
下面來看一個通過委託實現打招呼Greeting的例子(感謝張子陽先生的博文,此例選自其博文)
1.兩種不同的Greeting方式:
static void ChineseGreeting(string name)
{
Console.WriteLine("早上好,"+name);
}
static void EnglishGreeting(string name)
{
Console.WriteLine("Morning,"+name);
}
2.宣告一個委託:
public delegate void GreetingDelegate(string name);
3.封裝一個類,其中包含一個事件:
public class GreetingManager
{
public GreetingDelegate onGreeting;
public void ProcessGreeting(string name)
{
if (onGreeting != null)
{
onGreeting(name);
}
}
}
4.客戶端呼叫:
GreetingManager gm = new GreetingManager();
gm.onGreeting += EnglishGreeting;
gm.onGreeting += ChineseGreeting;
gm.ProcessGreeting("Edison Chou");
5.執行顯示結果:
Hello,Edison Chou
你好,Edison Chou
這裡有一個問題,如果將委託宣告為private許可權,那麼:“這簡直就是在搞笑。因為宣告委託的目的就是為了把它暴露在類的客戶端進行方法的註冊,你把它宣告為private了,客戶端對它根本就不可見,那它還有什麼用?”-(摘自張子陽的原話)
那麼如果就將委託設定為public,則客戶端可以清空監聽(即設定為null,因為它是引用型別),也可以偽造監聽(即直接呼叫委託),破壞了其封裝性。最後,第一個方法註冊用“=”,是賦值語法,因為要進行例項化,第二個方法註冊則用的是“+=”。但是,不管是賦值還是註冊,都是將方法繫結到委託上,除了呼叫時先後順序不同,再沒有任何的分別,這樣不是讓人覺得很彆扭麼?
該怎麼解決呢?於是Event事件閃亮登場了!!!它封裝了委託型別的變數,使得:在類的內部,不管你宣告它是public還是protected,它總是private的。在類的外部,註冊“+=”和登出“-=”的訪問限定符與你在宣告事件時使用的訪問符相同。
於是,我改寫GreetingManager類:
public class GreetingManager
{
public event GreetingDelegate onGreeting;
public void ProcessGreeting(string name)
{
if (onGreeting != null)
{
onGreeting(name);
}
}
}
這裡僅僅是加了一個event標誌,沒有神馬大的改變。但通過Reflector反編譯,可以看出事件其實就是一個封裝了的私有的委託而已,還包含兩個方法:add和remove;這兩個方法分別用於註冊委託型別的方法和取消註冊。實際上也就是: “+= ”對應 add_ProcessGreeting,“-=”對應remove_ProcessGreeting。而這兩個方法的訪問限制取決於宣告事件時的訪問限制符。所以,這下客戶端只能註冊、登出事件,無法進行偽造和清空事件,保證了封裝性。
3.委託和事件的區別
委託和事件沒有可比性,因為委託是型別,事件是物件。而委託的物件(用委託方式實現的事件)與標準event方式實現的事件的區別是:事件的內部是用委託實現的。