談及到C#的基本特性,“委托”是不得不去了解和深入分析的一個特性。對于大多數(shù)剛?cè)腴T的程序員談到“委托”時,都會想到“將方法作為方法的參數(shù)進行傳遞”,很多時候都只是知道簡單的定義,主要是因為“委托”在理解上有較其他特性比較難的地方。在本次說明中,不會將委托的簡單聲明和調(diào)用作為重點。
為南漳等地區(qū)用戶提供了全套網(wǎng)頁設計制作服務,及南漳網(wǎng)站建設行業(yè)解決方案。主營業(yè)務為成都網(wǎng)站制作、成都網(wǎng)站建設、南漳網(wǎng)站設計,以傳統(tǒng)方式定制建設網(wǎng)站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!“委托”不需要直接定義一個要執(zhí)行的行為,而是將這個行為用某種方法“包含”在一個對象中。這個對象可以像其他任何對象那樣使用。在該對象中,可以執(zhí)行封裝的操作??梢赃x擇將委托看作之定義了一個方法的接口,將委托的實例看作實現(xiàn)了那個接口的對象。
在“委托”的相關(guān)定義中,我們可以不難看出,“委托與方法“相比較于“接口與類”有著設計理念上的相似部分,產(chǎn)生的背景源于”設計原則“中的”開放-封閉原則“,”開放-封閉“原則:是說軟件實體(類,模塊,函數(shù)等等)應該可以擴展,但是不可修改。換一種說法可能更好的理解”對于擴展是開放的,對于更改是封閉的“,面對新的需求,對于程序的改動是通過增加新的代碼進行的,而不是更改現(xiàn)有的代碼。
在C#中委托用delegate關(guān)鍵字定義,使用new操作符構(gòu)造委托實例,采用傳統(tǒng)的方法調(diào)用語法來回調(diào)函數(shù)(只是要用引用了委托對象的一個變量代替方法名)。在C#中,委托在編譯的時候會被編譯成類。對于委托的一個說明:委托是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數(shù)來進行傳遞。委托類既可嵌套在一個類型中定義,也可以在全局范圍內(nèi)定義。由于委托是類,凡是可以定義類的地方,都可以定義委托。
接下來我們來看一下”委托“的組成,需要滿足的條件:
1.聲明委托類型。
2.必須有一個方法包含了要執(zhí)行的代碼。
3.必須創(chuàng)建一個委托實例。
4.必須調(diào)用委托實例。
接下來大致的了解一下上面所提出的4項條件:
委托類型實際上只是參數(shù)類型的一個列表以及返回類型。規(guī)定了類型的實例能表示的操作。在調(diào)用一個委托實例的時候,必須保證使用的參數(shù)完全匹配,而且能以指定的方式使用返回值。對于委托實例的創(chuàng)建,取決于操作使用實例方法還是靜態(tài)方法(如果操作是靜態(tài)方法,指定類型名稱就可以,如果是操作實例方法,需要先創(chuàng)建類型的實例)。對于委托的調(diào)用,可以直接調(diào)用委托的實例的方法就可以完成對應的操作。
以上談及了”委托“的定義和組成,接下來我們來了解一下如何將方法綁定到”委托“上,以及委托的合并和刪除。
可以將多個方法賦給同一個委托,委托實例實際有一個操作列表與之關(guān)聯(lián)。在System.Delegate類型中提供了兩個靜態(tài)方法Combine()和Remove()負責委托實例的新增和刪除操作。但是在我們的實際開發(fā)中,較多的采用-=和+=操作符。
在FCL中,所有的委托類型都派生自MulticastDelegate,該類型在System.MulticastDelegate類型中。
具體來看一下Combine()方法的底層實現(xiàn)代碼:
[System.Runtime.InteropServices.ComVisible(true)] public static Delegate Combine(params Delegate[] delegates) { if (delegates == null || delegates.Length == 0) return null; Delegate d = delegates[0]; for (int i = 1; i < delegates.Length; i++) d = Combine(d,delegates[i]); return d; }
public static Delegate Combine(Delegate a, Delegate b) { if ((Object)a == null) return b; return a.CombineImpl(b); }
以上兩個方法為System.Delegate類型中,CombineImpl方法在MulticastDelegate重寫。
[System.Security.SecuritySafeCritical] protected override sealed Delegate CombineImpl(Delegate follow) { if ((Object)follow == null) return this; if (!InternalEqualTypes(this, follow)) throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTypeMis")); MulticastDelegate dFollow = (MulticastDelegate)follow; Object[] resultList; int followCount = 1; Object[] followList = dFollow._invocationList as Object[]; if (followList != null) followCount = (int)dFollow._invocationCount; int resultCount; Object[] invocationList = _invocationList as Object[]; if (invocationList == null) { resultCount = 1 + followCount; resultList = new Object[resultCount]; resultList[0] = this; if (followList == null) { resultList[1] = dFollow; } else { for (int i = 0; i < followCount; i++) resultList[1 + i] = followList[i]; } return NewMulticastDelegate(resultList, resultCount); } else { int invocationCount = (int)_invocationCount; resultCount = invocationCount + followCount; resultList = null; if (resultCount <= invocationList.Length) { resultList = invocationList; if (followList == null) { if (!TrySetSlot(resultList, invocationCount, dFollow)) resultList = null; } else { for (int i = 0; i < followCount; i++) { if (!TrySetSlot(resultList, invocationCount + i, followList[i])) { resultList = null; break; } } } } if (resultList == null) { int allocCount = invocationList.Length; while (allocCount < resultCount) allocCount *= 2; resultList = new Object[allocCount]; for (int i = 0; i < invocationCount; i++) resultList[i] = invocationList[i]; if (followList == null) { resultList[invocationCount] = dFollow; } else { for (int i = 0; i < followCount; i++) resultList[invocationCount + i] = followList[i]; } } return NewMulticastDelegate(resultList, resultCount, true); } }
再來具體看一下Remove()方法的底層實現(xiàn)代碼,RemoveAll和Remove兩個方法為System.Delegate類型中,CombineImpl方法在MulticastDelegate重寫。
public static Delegate RemoveAll(Delegate source, Delegate value) { Delegate newDelegate = null; do { newDelegate = source; source = Remove(source, value); } while (newDelegate != source); return newDelegate; }
[System.Security.SecuritySafeCritical] public static Delegate Remove(Delegate source, Delegate value) { if (source == null) return null; if (value == null) return source; if (!InternalEqualTypes(source, value)) throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTypeMis")); return source.RemoveImpl(value); }
[System.Security.SecuritySafeCritical] protected override sealed Delegate RemoveImpl(Delegate value) { MulticastDelegate v = value as MulticastDelegate; if (v == null) return this; if (v._invocationList as Object[] == null) { Object[] invocationList = _invocationList as Object[]; if (invocationList == null) { if (this.Equals(value)) return null; } else { int invocationCount = (int)_invocationCount; for (int i = invocationCount; --i >= 0; ) { if (value.Equals(invocationList[i])) { if (invocationCount == 2) { return (Delegate)invocationList[1-i]; } else { Object[] list = DeleteFromInvocationList(invocationList, invocationCount, i, 1); return NewMulticastDelegate(list, invocationCount-1, true); } } } } } else { Object[] invocationList = _invocationList as Object[]; if (invocationList != null) { int invocationCount = (int)_invocationCount; int vInvocationCount = (int)v._invocationCount; for (int i = invocationCount - vInvocationCount; i >= 0; i--) { if (EqualInvocationLists(invocationList, v._invocationList as Object[], i, vInvocationCount)) { if (invocationCount - vInvocationCount == 0) { return null; } else if (invocationCount - vInvocationCount == 1) { return (Delegate)invocationList[i != 0 ? 0 : invocationCount-1]; } else { Object[] list = DeleteFromInvocationList(invocationList, invocationCount, i, vInvocationCount); return NewMulticastDelegate(list, invocationCount - vInvocationCount, true); } } } } } return this; }
在以上的代碼中,我們了解到了在.NET底層是如何實現(xiàn)委托實例的綁定和刪除綁定。
在調(diào)用委托實例時,所有的操作都是順序執(zhí)行的。如果調(diào)用具有一個非void的返回類型,則調(diào)用的返回值是最后一個操作的返回值。如果調(diào)用列表中任何操作拋出異常,都會阻止執(zhí)行后續(xù)的操作。
在上面提到了委托列表中出現(xiàn)非void實例調(diào)用,如果委托實例中出現(xiàn)多個非void調(diào)用,并且需要獲取所有的委托實例的返回值結(jié)果,那么應該如何操作,在.NET紅提供了一個方法GetInvocationList(),用于獲取委托鏈表。
接下來具體了解一下GetInvocationList()的底層代碼:
[System.Security.SecuritySafeCritical] public override sealed Delegate[] GetInvocationList() { Delegate[] del; Object[] invocationList = _invocationList as Object[]; if (invocationList == null) { del = new Delegate[1]; del[0] = this; } else { int invocationCount = (int)_invocationCount; del = new Delegate[invocationCount]; for (int i = 0; i < invocationCount; i++) del[i] = (Delegate)invocationList[i]; } return del; }
當獲取到委托實例列表后,可采用循環(huán)迭代的方式,依次獲取每個委托實例的返回值。
再來了解一個屬性Method,具體看一下此屬性的底層實現(xiàn)代碼:
public MethodInfo Method { get { return GetMethodImpl(); } } [System.Security.SecuritySafeCritical] protected virtual MethodInfo GetMethodImpl() { if ((_methodBase == null) || !(_methodBase is MethodInfo)) { IRuntimeMethodInfo method = FindMethodHandle(); RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(method); if (RuntimeTypeHandle.IsGenericTypeDefinition(declaringType) || RuntimeTypeHandle.HasInstantiation(declaringType)) { bool isStatic = (RuntimeMethodHandle.GetAttributes(method) & MethodAttributes.Static) != (MethodAttributes)0; if (!isStatic) { if (_methodPtrAux == (IntPtr)0) { Type currentType = _target.GetType(); Type targetType = declaringType.GetGenericTypeDefinition(); while (currentType != null) { if (currentType.IsGenericType && currentType.GetGenericTypeDefinition() == targetType) { declaringType = currentType as RuntimeType; break; } currentType = currentType.BaseType; } BCLDebug.Assert(currentType != null || _target.GetType().IsCOMObject, "The class hierarchy should declare the method"); } else { MethodInfo invoke = this.GetType().GetMethod("Invoke"); declaringType = (RuntimeType)invoke.GetParameters()[0].ParameterType; } } } _methodBase = (MethodInfo)RuntimeType.GetMethodBase(declaringType, method); } return (MethodInfo)_methodBase; }
以上是System.Delegate類中的定義,接下來看一下MulticastDelegate重寫:
[System.Security.SecuritySafeCritical] protected override MethodInfo GetMethodImpl() { if (_invocationCount != (IntPtr)0 && _invocationList != null) { Object[] invocationList = _invocationList as Object[]; if (invocationList != null) { int index = (int)_invocationCount - 1; return ((Delegate)invocationList[index]).Method; } MulticastDelegate innerDelegate = _invocationList as MulticastDelegate; if (innerDelegate != null) { return innerDelegate.GetMethodImpl(); } } else if (IsUnmanagedFunctionPtr()) { if ((_methodBase == null) || !(_methodBase is MethodInfo)) { IRuntimeMethodInfo method = FindMethodHandle(); RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(method); if (RuntimeTypeHandle.IsGenericTypeDefinition(declaringType) || RuntimeTypeHandle.HasInstantiation(declaringType)) { RuntimeType reflectedType = GetType() as RuntimeType; declaringType = reflectedType; } _methodBase = (MethodInfo)RuntimeType.GetMethodBase(declaringType, method); } return (MethodInfo)_methodBase; } return base.GetMethodImpl(); }
以上是對委托的相關(guān)定義,以及有關(guān)委托的一些操作方法的說明,沒有具體指出如何去創(chuàng)建和使用委托,因為委托的簡單創(chuàng)建和一般應用,對于大部分開發(fā)者來說是相對較為簡單的,因為微軟在不斷的對C#的語法進行提升和修改,極大的簡化了對應的操作。但是正是由于在應用層做了較大的封裝,這也會導致特性在底層的復雜度慢慢的增大。
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡助力業(yè)務部署。公司持有工信部辦法的idc、isp許可證, 機房獨有T級流量清洗系統(tǒng)配攻擊溯源,準確進行流量調(diào)度,確保服務器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務器買多久送多久。
文章題目:C#中的委托解析-創(chuàng)新互聯(lián)
文章轉(zhuǎn)載:http://muchs.cn/article48/pgihp.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、網(wǎng)頁設計公司、響應式網(wǎng)站、關(guān)鍵詞優(yōu)化、搜索引擎優(yōu)化、網(wǎng)站營銷
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容