代码改变世界

C# Delegates And Events in Depth[翻译加笔记]【Delegate】【1】

2011-08-14 22:53  一一九九  阅读(326)  评论(0编辑  收藏  举报

http://www.ikriv.com/en/prog/info/dotnet/Delegates.html

这篇文章涉及的主题主要有如下几点:

  • class delegate
  • class multicastDelegate
  • Field-like events
  • event accessors
  • Virtual events

Delegate class

        任何一个Delegate Object 都是隐含的从类Delegate继承下来的。类Delegate是一个比较特殊的类,这个类只有系统和编译器创建的类型能够继承自它,其他的任务用户自定义类型都不能明确表明要继承自Delegate类。

       Delegate 类有两个主要的Properties: Target和Method。 Target指向了一个对象的实例,Method描述了被那个实力实现的方法。调用Delegate意味着让Target Object调用其上的方法。

       示例:

    delegate void MyDelegate();
    public class MyClass
    {
        public void SomeMethod()
        {
            Console.WriteLine("SomeMethod is called");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyClass o = new MyClass();
            MyDelegate del  = new MyDelegate(o.SomeMethod);
            del();
            Console.WriteLine("done");
            Console.Read();
        }
    }

 

Delegate and Static Methods

      如果Delegate是指向一个静态的方法的时候会有什么情况出现呢?

      在这种情况下,如果获取Delegate的Target的属性将得到NULL值,实际上,Delegat在内部将Target存储到一个私有的变量_target中, 一般来说,属性Target会返回_target的值,但是对于StaticDelegate来说, _target包含了一个指向Delegate 自己的引用,Target属性的Get方法会做一个快速的检测, 如果_target是指向了自己,那么返回NULL。

        示例代码:

    delegate void MyDelegate();
    public class MyClass
    {
        public void SomeMethod()
        {
            Console.WriteLine("SomeMethod is called");
        }
        public static void SomeStaticMethod()
        {
            Console.WriteLine("Some static method");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyClass o = new MyClass();
            MyDelegate del  = new MyDelegate(o.SomeMethod);
            del();
            MyDelegate staticDel = new MyDelegate(MyClass.SomeStaticMethod);
            Console.WriteLine(staticDel.ToString());
            if(staticDel.Target != null)
                Console.WriteLine(staticDel.Target.ToString());
            else
                Console.WriteLine("Target is null");
            Console.WriteLine(staticDel.Method.ToString());
            staticDel();
            Console.WriteLine("done");
            Console.Read();
        }
    }

 

Equality of Delegates

      非静态的委托当Target和Method都相等的时候是相等的。这就是说即使委托属于不同的类型但是如果指向的是同一个方法那么可以认为他们是相等的。如下代码,是可以认为委托是相等的。
        示例代码:

 public class DelegateEqulity
    {
        delegate void DelegateA();
        delegate void DelegateB();
        public void SomeMethod()
        {
            Console.WriteLine("They are equal");
        }
        public void DoTestDelegateEqulity()
        {
            //DelegateEqulity o = new DelegateEqulity();
            //DelegateA a = new DelegateA(o.SomeMethod);
            //DelegateB b = new DelegateB(o.SomeMethod);
            DelegateA a = new DelegateA(this.SomeMethod);
            DelegateB b = new DelegateB(this.SomeMethod);
            DelegateA A1 = new DelegateA(this.SomeMethod);
            if(a.Equals(b))
                Console.WriteLine("Equal");
            if(Object.Equals(a, b))
                Console.WriteLine("Equal");
            if(Object.ReferenceEquals(a, b))
                Console.WriteLine("Equal");
            if (a.Equals(A1))
                Console.WriteLine("xxxx Equal");
            if (Object.Equals(a, A1))
                Console.WriteLine("xxx Equal");
            if (Object.ReferenceEquals(a, A1))
                Console.WriteLine("ReferenceEquals");
        }

         这段话并没有作者说的那种,仍然是不相等的,只有同一个类型的类比较才是相等的,而且同一个类型的Delegate如果是不同的实例,此时Reference也是不Equal的。

       对Delegate进行Reflector以下,发现Equals仍然是进行类型判断的。如下:

[SecuritySafeCritical]
public override bool Equals(object obj)
{
    if ((obj == null) || !InternalEqualTypes(this, obj))
    {
        return false;
    }
    Delegate right = (Delegate) obj;
    if (((this._target == right._target) && (this._methodPtr == right._methodPtr)) && (this._methodPtrAux == right._methodPtrAux))
    {
        return true;
    }
    if (this._methodPtrAux.IsNull())
    {
        if (!right._methodPtrAux.IsNull())
        {
            return false;
        }
        if (this._target != right._target)
        {
            return false;
        }
    }
    else
    {
        if (right._methodPtrAux.IsNull())
        {
            return false;
        }
        if (this._methodPtrAux == right._methodPtrAux)
        {
            return true;
        }
    }
    if (((this._methodBase != null) && (right._methodBase != null)) && ((this._methodBase is MethodInfo) && (right._methodBase is MethodInfo)))
    {
        return this._methodBase.Equals(right._methodBase);
    }
    return InternalEqualMethodHandles(this, right);
}
 
 

MulticastDelegate Class

         MulticastDelegate是从类Delegate继承下来,代表一个可以激活多个方法的Delegate。所有的在C#中创建的的Delegate都是MultiCast Delegates.

        MulticastDelegate内部是delegate实现的一个List。 Delegate按照添加逆序保存,例如,如果按照以下代码操作:
       

Class1 object1 = new Class1();
Class2 object2 = new Class2();     
MyDelegate d = new MyDelegate(object1.Method1);
d += new MyDelegate(object2.Method2);

则Delegate d 在内存中的大体样子如下所示:
         image

激活这个Delegate是通过递归实现的, 激活代码首先激活前一个Delegate,最后地用Target.Method. 注意在这种情况下, Target 和Method属性代表最近添加的Delegate Method。
 

Adding and Removing Delegates
    略

Null Delegates
   
There is no such thing as delegate without an invocation list。Whenever invocation list becomes empty, delegate becomes null. Calling null delegate is a run-time error. Therefore, whenever someone calls a delegate, he/she must check it for null, or else

    如下:

MyDelegate a;
...
if (a != null)
{
    a( parameters );
}