程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#高級程序設計(二)——代理

C#高級程序設計(二)——代理

編輯:C#入門知識

本質上講,代理提供了方法的封裝,它把方法以某種方式封裝在一個代理對象裡,通過代理對象來執行調用方法、移除或者添加代理對象等操作。從另一種意義上講,你可以把代理類型看作單一方法的接口,代理對象看作實現了該接口的對象。
代理對象基礎:代理類型
下面的代碼定義了一個代理類型
[csharp] 
internal delegate void Feedback(Int32 value); 

C#編譯器實際上將這個代理類型轉化成為一個繼承自MulticastDelegate的類。
[csharp]
internal class Feedback : System.MulticastDelegate  

// Constructor 
public Feedback(Object object, IntPtr method); 
// Method with same prototype as specified by the source code 
public virtual void Invoke(Int32 value); 
// Methods allowing the callback to be called asynchronously 
public virtual IAsyncResult BeginInvoke(Int32 value, 
AsyncCallback callback, Object object); 
public virtual void EndInvoke(IAsyncResult result); 

MulticastDelegate繼承自Delegate類,下面是代理類的簽名:
[csharp]
public abstract class Delegate : ICloneable, ISerializable 
    { 
        protected Delegate(object target, string method); 
        protected Delegate(Type target, string method); 
 
        public static bool operator !=(Delegate d1, Delegate d2); 
        public static bool operator ==(Delegate d1, Delegate d2); 
 
        public MethodInfo Method { get; } 
        public object Target { get; } 
 
        public virtual object Clone(); 
        public static Delegate Combine(params Delegate[] delegates); 
        public static Delegate Combine(Delegate a, Delegate b); 
        protected virtual Delegate CombineImpl(Delegate d); 
        public static Delegate CreateDelegate(Type type, MethodInfo method); 
        public static Delegate CreateDelegate(Type type, MethodInfo method, bool throwOnBindFailure); 
        public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method); 
        public static Delegate CreateDelegate(Type type, object target, string method); 
        public static Delegate CreateDelegate(Type type, Type target, string method); 
        public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method, bool throwOnBindFailure); 
        public static Delegate CreateDelegate(Type type, object target, string method, bool ignoreCase); 
        public static Delegate CreateDelegate(Type type, Type target, string method, bool ignoreCase); 
        public static Delegate CreateDelegate(Type type, object target, string method, bool ignoreCase, bool throwOnBindFailure); 
        public static Delegate CreateDelegate(Type type, Type target, string method, bool ignoreCase, bool throwOnBindFailure); 
        public object DynamicInvoke(params object[] args); 
        protected virtual object DynamicInvokeImpl(object[] args); 
        public override bool Equals(object obj); 
        public override int GetHashCode(); 
        public virtual Delegate[] GetInvocationList(); 
        protected virtual MethodInfo GetMethodImpl(); 
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context); 
        public static Delegate Remove(Delegate source, Delegate value); 
        public static Delegate RemoveAll(Delegate source, Delegate value); 
        protected virtual Delegate RemoveImpl(Delegate d); 
    } 

這樣的轉化實際上定義了代理對象所有可能的操作,下面將一一列出
一、構造並初始化代理對象
最常見的方式是使用下面的方式來構造並初始化代理對象
[csharp]
Feedback fbInstance = new Feedback(new Program().FeedbackToFile); 

然而,隨著C#版本的升級,越來越多和代理有關的特性隨之引入,同時也改變了代理對象的構造並初始化方式,例如在C#3.0中就可以用匿名方法或者lambda表達式來構造並初始化代理對象。
二、調用代理對象封裝的方法
這實際上是調用代理定義時編譯器所生成的Invoke或者BeginInvoke方法,一個用於同步調用,另一個用於異步調用。
[csharp] 
fbInstance.Invoke(1);  

但是,C#做了進一步優化,你可以直接通過代理對象來調用其所封裝的方法,例如:
[csharp]
fbInstance(1);  

三、連接和移除代理對象
前面看到的代理對象都是封裝一個方法,實際上,代理對象可以將一系列方法封裝成一個鏈表,這一特性取決於Delegate類的Combine和Remove方法。
[csharp]
fbChain = (Feedback) Delegate.Combine(fbChain, fb1); 

實際上,C#對這一用法也提供了優化,可以使用+、+=、-、-=運算符來添加或移除代理對象:
[csharp] 
fbChain += fb1;  

代理的擴展:事件
C#事件的引入類似屬性的引入,屬性是對字段的封裝,而事件對象是對代理對象的封裝。
當定義如下事件時:
[csharp] 
public event EventHandler<NewMailEventArgs> NewMail; 

C#編譯器實際上會將其轉換成如下的代碼:
[csharp]
// 1. A PRIVATE delegate field that is initialized to null 
private EventHandler<NewMailEventArgs> NewMail = null; 
// 2. A PUBLIC add_Xxx method (where Xxx is the Event name) 
// Allows methods to register interest in the event. 
public void add_NewMail(EventHandler<NewMailEventArgs> value) { 
// The loop and the call to CompareExchange is all just a fancy way 
// of adding a delegate to the event in a thread-safe way 
EventHandler<NewMailEventArgs>prevHandler; 
EventHandler<NewMailEventArgs> newMail = this.NewMail; 
do { 
prevHandler = newMail; 
EventHandler<NewMailEventArgs>newHandler = 
(EventHandler<NewMailEventArgs>) Delegate.Combine(prevHandler, value); 
newMail = Interlocked.CompareExchange<EventHandler<NewMailEventArgs>>( 
ref this.NewMail, newHandler, prevHandler); 
} while (newMail != prevHandler); 

// 3. A PUBLIC remove_Xxx method (where Xxx is the Event name) 
// Allows methods to unregister interest in the event. 
public void remove_NewMail(EventHandler<NewMailEventArgs> value) { 
// The loop and the call to CompareExchange is all just a fancy way 
// of removing a delegate from the event in a thread-safe way 
EventHandler<NewMailEventArgs> prevHandler; 
EventHandler<NewMailEventArgs> newMail = this.NewMail; 
do { 
prevHandler = newMail; 
EventHandler<NewMailEventArgs> newHandler = 
(EventHandler<NewMailEventArgs>) Delegate.Remove(prevHandler, value); 
newMail = Interlocked.CompareExchange<EventHandler<NewMailEventArgs>>( 
ref this.NewMail, newHandler, prevHandler); 
} while (newMail != prevHandler); 

從上面生成的代碼可以看出,事件對象封裝了類中的代理對象,並且只暴露出add_xxx和remove_xxx方法(事件對象的+=和-=即調用相應的方法),而外界無法對其封裝的代理對象進行額外的操作(構建並初始化代理對象、調用代理對象封裝的方法)。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved