日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET Framework源码研究系列之---Delegate

發布時間:2023/12/13 asp.net 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET Framework源码研究系列之---Delegate 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

  曾幾何時能看到微軟產品的源碼簡直是天方夜譚,不過現在這卻成了現實,微軟終于對外開放了它的產品的源代碼.拋去開源運動與微軟之間的世代情仇,拋去微軟這一做法的初衷,這總歸是件好事,能夠讓我們撥開云霧,一窺優秀產品的秘密.

  前兩天看到有位仁兄在隨筆中的留言,說他以為".NET中的設計模式"是在講.NET Framework與設計模式的關系,其實不是,不過這也讓我想起來自己確實研究過.NET Framework的源碼,于是就找打算找時間把自己的心得體會拿出來和大家一起分享.

  今天就先從最容易讓人困惑的委托(delegate)開始,讓我們步入.NET Framework源碼世界,共同學習優秀的程序設計.

  先看委托的定義:用于聲明一個引用類型,該引用類型可用于封裝命名方法或匿名方法。委托類似于 C++ 中的函數指針;但是,委托是類型安全和可靠的。

  相信看到這段話之后,很多人,包括我自己就開始一起探索委托函數指針,于是各種網文就出現了.但委托到底是什么呢?我們先看一段很簡單的代碼:

?

public delegate void OnAction(int flag);

這里我們定義了一個最簡單的委托:OnAction.MSDN解釋Delegate 類是委托類型的基類,但只有系統和編譯器可以顯式地從 Delegate 類或 MulticastDelegate 類派生.那么我們可以認為OnAction是從delegate繼承過來的,只是不能顯式的繼承,由系統代做了.

  接下來讓我們看一下微軟是怎么定義委托的:

?

[Serializable()]
[ClassInterface(ClassInterfaceType.AutoDual)]
[System.Runtime.InteropServices.ComVisible(
true)]
public abstract class Delegate : ICloneable, ISerializable

由此可以看出delegate是個抽象類,并且實現了?ICloneable, ISerializable兩個接口,并且有ClassInterface(ClassInterfaceType.AutoDual)這么一個屬性.這有很多問題.

  首先,委托是個抽象類,所以要使用的必須繼承,但是委托又跟整型一樣,是一種類型,由此就可以理解問什么"Delegate 類是委托類型的基類,但只有系統和編譯器可以顯式地從 Delegate 類或 MulticastDelegate 類派生"這句話的意思了,因為不可能從整型繼承過來一個子類,那么委托為什么是一個類而不像整型一樣是一個結構呢?這個問題下面回答.

  其次,這也是我覺得不理解的地方,委托實現了ICloneable, ISerializable兩個接口,也就是說委托可以被克隆和序列化.相信大家沒人會寫OnAction.Clone();這么一句話.淺表克隆一個委托實在有點費解.不過,如果可以從良好的編程習慣上解釋為什么事先ICloneable接口的話,委托對ISerializable的實現就更讓人困惑了,因為可能因此導致一些莫名其妙的編譯時錯誤.我曾經遇到這樣一個Bug,一個標記序列化的單件實體類包含一個事件(事件默認實現了ISerializable),該事件導致序列化的時候在凡是跟該事件的引用有關的地方全部報出莫名其妙的未標記序列化的錯誤,最終的解決辦法是需要將該事件標記為[NonSerialized].

????? 下面看一下具體是怎么實現委托的:

?

代碼 public abstract class Delegate : ICloneable, ISerializable
{
//要調用的對象
internal Object _target;

// MethodBase, either cached after first request or assigned from a DynamicMethod
internal MethodBase _methodBase;

// _methodPtr is a pointer to the method we will invoke
// It could be a small thunk if this is a static or UM call
internal IntPtr _methodPtr;

// In the case of a static method passed to a delegate, this field stores
// whatever _methodPtr would have stored: and _methodPtr points to a
// small thunk which removes the "this" pointer before going on
// to _methodPtrAux.
internal IntPtr _methodPtrAux;

// This constructor is called from the class generated by the
// compiler generated code
protected Delegate(Object target, String method)
{
if (target == null)
throw new ArgumentNullException("target");

if (method == null)
throw new ArgumentNullException("method");

// This API existed in v1/v1.1 and only expected to create closed
// instance delegates. Constrain the call to BindToMethodName to
// such and don't allow relaxed signature matching (which could make
// the choice of target method ambiguous) for backwards
// compatibility. The name matching was case sensitive and we
// preserve that as well.
if (!BindToMethodName(target, Type.GetTypeHandle(target), method,
DelegateBindingFlags.InstanceMethodOnly
|
DelegateBindingFlags.ClosedDelegateOnly))
throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTargMeth"));
}

// This constructor is called from a class to generate a
// delegate based upon a static method name and the Type object
// for the class defining the method.
protected unsafe Delegate(Type target, String method)
{
if (target == null)
throw new ArgumentNullException("target");

if (!(target is RuntimeType))
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "target");

if (target.IsGenericType && target.ContainsGenericParameters)
throw new ArgumentException(Environment.GetResourceString("Arg_UnboundGenParam"), "target");

if (method == null)
throw new ArgumentNullException("method");

// This API existed in v1/v1.1 and only expected to create open
// static delegates. Constrain the call to BindToMethodName to such
// and don't allow relaxed signature matching (which could make the
// choice of target method ambiguous) for backwards compatibility.
// The name matching was case insensitive (no idea why this is
// different from the constructor above) and we preserve that as
// well.
BindToMethodName(null, target.TypeHandle, method,
DelegateBindingFlags.StaticMethodOnly
|
DelegateBindingFlags.OpenDelegateOnly
|
DelegateBindingFlags.CaselessMatching);
}

// Protect the default constructor so you can't build a delegate
private Delegate()
{
}

上面代碼顯示委托類包含4個internal類型的字段,從其注釋我們大致可以看出_target是我們要調用的對象,_methodBase是給委托賦值時傳遞的方法,_methodPtr是指向該方法的指針,_methodPtrAux同靜態類型委托的methodPtr指向的內容一樣,只是少了對象的引用. 在看委托類的三個構造函數,一個是私有的,是用來防止實例化的,另外2個差不多,做的事情是把一個方法綁定到一個對象上.這里的方法應該是我們賦給委托的方法,對象則是編譯器自己來維護的對象.這里調用了一個方法BindToMethodName,在源碼中看不到實現,僅能看到如下內容:

[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern bool BindToMethodName(Object target, RuntimeTypeHandle methodType, String method, DelegateBindingFlags flags);

MethodImplAttribute標簽表明了該方法為CLR內部方法,具體是什么,我們不得而知.此類的方法還有很多,就不一一例舉.說到這個地方,我們可以發現上面說的"OnAction是從delegate繼承過來的"和"Delegate 類是委托類型的基類"并不正確,正確的理解應該是delegate類在內部管理了一個用于綁定方法的對象,這點也可以從OnAction反匯編出來的構造函數看出:

代碼 .method public hidebysig specialname rtspecialname
instance
void .ctor(object 'object',
native
int 'method') runtime managed
{
}
// end of method OnAction::.ctor

另外delegate中還有一個靜態方法:

public static Delegate CreateDelegate(Type type, Object firstArgument, MethodInfo method, bool throwOnBindFailure)

該方法前后有11個重載,其方法體里無一不包括:

?

代碼 Delegate d = InternalAlloc(type.TypeHandle);
if (!d.BindToMethodInfo(firstArgument, method.MethodHandle, method.DeclaringType.TypeHandle,
DelegateBindingFlags.RelaxedSignature))
{
if (throwOnBindFailure)
throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTargMeth"));
d
= null;
}

這樣一段代碼.其中InternalAlloc,BindToMethodInfo與BindToMethodName一樣,都屬于CLR內部方法.具體是什么一樣看不出,只能大致猜測CLR內部生成了一個委托對象,然后將我們定義的委托簽名,方法,方法引用等一些內容交給委托類來維護.

?

  通過以上分析,我們發現如它的定義,委托本質上是一個類,它的職責是代替我們管理維護方法調用.這一切無論從功能,還是外面,其實跟函數指針沒有半點關系.至此,相信大家對delegate有了不一樣的認識,同時也發現C#僅僅是CLR的一層外殼,并沒有涉及到很核心的內容.

?

?

?

?

?????? 以上僅僅是我個人的一點看法,由于本人水平有限,認識上難免有不正確的地方,如果你有更好的見解,敬請指正.

轉載于:https://www.cnblogs.com/niyw/archive/2010/07/22/1783306.html

總結

以上是生活随笔為你收集整理的.NET Framework源码研究系列之---Delegate的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。