C#委托深入解析

      委托对于学习C#语言得初学者,一定是一个阻碍,最起码对我来说,最开始只知道怎么用,直到工作了两三年,才彻底搞懂里面得含义。也可能是我个人比较笨吧。

1.1  C语言指针

      了解委托之前先了解下c的指针函数。如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。

函数指针的使用:

#include <stdio.h>
#include<iostream>
int Count(int a, int b);
int main() {
	int (*p)(int, int);
	p = Count;
	int c = p(10, 20);
	std::cout << c;
}
int Count(int a,int b) {
	return a + b;
}

1.2 初识委托

        委托是一种存储函数引用的类型,在事件和事件的处理时有重要的用途通俗的说,委托是一个可以引用方法的类型,当创建一个委托,也就创建一个引用方法的变量,进而就可以调用那个方法,即委托可以调用它所指的方法。委托也可以简单理解为指向方法得指针。

1.2.1  委托代码示例(来源CLR VIA C#)

       下面这串代码并不难,新手也能看懂。照着写一遍。

 class Program
    {
        private delegate void FeedBack(Int32 item);
        static void Main(string[] args)
        {
            ChainDelegateDemo2();
        }

       //委托调用静态方法
        private static void DelegateStaticDemo()
        {
            ShowCount(1, 20, null);
            ShowCount(1, 20, new FeedBack(FeedbackConsole));
            ShowCount(1, 20, new FeedBack(FeedbackMessageBox));
            
            
            Console.ReadKey();

        }
        //委托调用实例方法
        private static void InstanceDelegateDemo()
        {
            
            ShowCount(1, 20, new Program().FeedbackStream);
            Console.ReadLine();
        }
        //委托调用实例方法
        private static void ChainDelegateDemo()
        {
            FeedBack fb1 = new FeedBack(FeedbackConsole);
            FeedBack fb2 = new FeedBack(FeedbackMessageBox);
            FeedBack fb3 = new FeedBack(new Program(). FeedbackStream);
            FeedBack fc = null;
            fc = (FeedBack)Delegate.Combine(fc, fb1);
            fc = (FeedBack)Delegate.Combine(fc, fb2);
            fc = (FeedBack)Delegate.Combine(fc, fb3);
         //   ShowCount(1, 2, fc);
            fc=(FeedBack) Delegate.Remove(fc, new FeedBack(FeedbackConsole));
            ShowCount(1, 2, fc);
            Console.ReadKey();
        }
        private static void ChainDelegateDemo2()
        {
            FeedBack fb1 = new FeedBack(FeedbackConsole);
            FeedBack fb2 = new FeedBack(FeedbackMessageBox);
            FeedBack fb3 = new FeedBack(new Program().FeedbackStream);
            FeedBack fc = null;
            fc += fb1;
            fc += fb2;
            fc += fb3;
            fc -= fb1;
            //   ShowCount(1, 2, fc);
         
            ShowCount(1, 2, fc);
            Console.ReadKey();
        }
        private static void ShowCount(Int32 from, Int32 to, FeedBack fb)
        {
            for (int i = from; i <= to; i++)
            {
                if (fb != null)
                    fb(i);
            }
        }
        private static void FeedbackConsole(Int32 item)
        {
            Console.WriteLine(item.ToString());
        }
        private static void FeedbackMessageBox(Int32 item)
        {
            MessageBox.Show (item.ToString());
        }
        private void FeedbackStream(Int32 item)
        {
            using(StreamWriter st=new StreamWriter("ssss", true))
            {
                st.Write(item.ToString());
            }
        }
    }

当前所有得方法都写到一个类里面了,其实这些方法即使写入其他类里面,只要委托类型足够安全,便没有任何问题.

1.2.2 委托得逆变性和协变性

逆变性:方法获得得参数可以是委托得参数类型得基类。

协变性性:方法能发挥委托返回类型派生得类型

delegate object macll(FileStream st)

string Methond(Stream st)

在这里,返回值类型是委托得派生类,协变性允许,FileStream是Stream子类,逆变性允许

1.2.3 委托解密

首先看一下委托得IL代码

.class nested private auto ansi sealed FeedBack
	extends [mscorlib]System.MulticastDelegate
{
	// Methods
	.method public hidebysig specialname rtspecialname 
		instance void .ctor (
			object 'object',
			native int 'method'
		) runtime managed 
	{
	} // end of method FeedBack::.ctor

	.method public hidebysig newslot virtual 
		instance void Invoke (
			int32 item
		) runtime managed 
	{
	} // end of method FeedBack::Invoke

	.method public hidebysig newslot virtual 
		instance class [mscorlib]System.IAsyncResult BeginInvoke (
			int32 item,
			class [mscorlib]System.AsyncCallback callback,
			object 'object'
		) runtime managed 
	{
	} // end of method FeedBack::BeginInvoke

	.method public hidebysig newslot virtual 
		instance void EndInvoke (
			class [mscorlib]System.IAsyncResult result
		) runtime managed 
	{
	} // end of method FeedBack::EndInvoke

} // end of class FeedBack

定义得委托自动继承了System.MulticastDelegate,所有得委托均继承此类,编译器定义了四个方法,一个构造器,一个Invoke,一个BeginInvoke,一个EndInvoke。

由于所有委托类型都继承System.MulticastDelegate,所以也继承System.MulticastDelegate的属性和方法,在所有属性和方法里面,有三个非公字段是最重要的。

tip:MulticastDelegate是一个特殊的类,编译器和其他工具可以派生,代码里不可以显示派生。

Source Browser  可以在这里看MulticastDelegate的源代码

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
 
namespace System
{
    [ClassInterface(ClassInterfaceType.None)]
    [ComVisible(true)]
    public abstract class MulticastDelegate : Delegate
    {
        // This is set under 2 circumstances
        // 1. Multicast delegate
        // 2. Wrapper delegate
        private object? _invocationList; // Initialized by VM as needed
        private IntPtr _invocationCount;
 
        // This constructor is called from the class generated by the
        //    compiler generated code (This must match the constructor
        //    in Delegate
        [RequiresUnreferencedCode("The target method might be removed")]
        protected MulticastDelegate(object target, string method) : base(target, method)
        {
        }
 
        // 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 MulticastDelegate([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type target, string method) : base(target, method)
        {
        }
 
        internal bool IsUnmanagedFunctionPtr()
        {
            return _invocationCount == (IntPtr)(-1);
        }
 
        internal bool InvocationListLogicallyNull()
        {
            return (_invocationList == null) || (_invocationList is LoaderAllocator) || (_invocationList is System.Reflection.Emit.DynamicResolver);
        }
 
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            throw new SerializationException(SR.Serialization_DelegatesNotSupported);
        }
 
        // equals returns true IIF the delegate is not null and has the
        //    same target, method and invocation list as this object
        public sealed override bool Equals([NotNullWhen(true)] object? obj)
        {
            if (obj == null)
                return false;
            if (object.ReferenceEquals(this, obj))
                return true;
            if (!InternalEqualTypes(this, obj))
                return false;
 
            // Since this is a MulticastDelegate and we know
            // the types are the same, obj should also be a
            // MulticastDelegate
            Debug.Assert(obj is MulticastDelegate, "Shouldn't have failed here since we already checked the types are the same!");
            MulticastDelegate d = Unsafe.As<MulticastDelegate>(obj);
 
            if (_invocationCount != (IntPtr)0)
            {
                // there are 4 kind of delegate kinds that fall into this bucket
                // 1- Multicast (_invocationList is Object[])
                // 2- Wrapper (_invocationList is Delegate)
                // 3- Unmanaged FntPtr (_invocationList == null)
                // 4- Open virtual (_invocationCount == MethodDesc of target, _invocationList == null, LoaderAllocator, or DynamicResolver)
 
                if (InvocationListLogicallyNull())
                {
                    if (IsUnmanagedFunctionPtr())
                    {
                        if (!d.IsUnmanagedFunctionPtr())
                            return false;
 
                        return CompareUnmanagedFunctionPtrs(this, d);
                    }
 
                    // now we know 'this' is not a special one, so we can work out what the other is
                    if (d._invocationList is Delegate)
                        // this is a wrapper delegate so we need to unwrap and check the inner one
                        return Equals(d._invocationList);
 
                    return base.Equals(obj);
                }
                else
                {
                    if (_invocationList is Delegate invocationListDelegate)
                    {
                        // this is a wrapper delegate so we need to unwrap and check the inner one
                        return invocationListDelegate.Equals(obj);
                    }
                    else
                    {
                        Debug.Assert(_invocationList is object[], "empty invocation list on multicast delegate");
                        return InvocationListEquals(d);
                    }
                }
            }
            else
            {
                // among the several kind of delegates falling into this bucket one has got a non
                // empty _invocationList (open static with special sig)
                // to be equals we need to check that _invocationList matches (both null is fine)
                // and call the base.Equals()
                if (!InvocationListLogicallyNull())
                {
                    if (!_invocationList!.Equals(d._invocationList))
                        return false;
                    return base.Equals(d);
                }
 
                // now we know 'this' is not a special one, so we can work out what the other is
                if (d._invocationList is Delegate)
                    // this is a wrapper delegate so we need to unwrap and check the inner one
                    return Equals(d._invocationList);
 
                // now we can call on the base
                return base.Equals(d);
            }
        }
 
        // Recursive function which will check for equality of the invocation list.
        private bool InvocationListEquals(MulticastDelegate d)
        {
            Debug.Assert(d != null);
            Debug.Assert(_invocationList is object[]);
            object[] invocationList = (object[])_invocationList;
 
            if (d._invocationCount != _invocationCount)
                return false;
 
            int invocationCount = (int)_invocationCount;
            for (int i = 0; i < invocationCount; i++)
            {
                Debug.Assert(invocationList[i] is Delegate);
                Delegate dd = (Delegate)invocationList[i]; // If invocationList is an object[], it always contains Delegate (or MulticastDelegate) objects
 
                object[] dInvocationList = (d._invocationList as object[])!;
                if (!dd.Equals(dInvocationList[i]))
                    return false;
            }
            return true;
        }
 
        private static bool TrySetSlot(object?[] a, int index, object o)
        {
            if (a[index] == null && System.Threading.Interlocked.CompareExchange<object?>(ref a[index], o, null) == null)
                return true;
 
            // The slot may be already set because we have added and removed the same method before.
            // Optimize this case, because it's cheaper than copying the array.
            if (a[index] is object ai)
            {
                MulticastDelegate d = (MulticastDelegate)o;
                MulticastDelegate dd = (MulticastDelegate)ai;
 
                if (dd._methodPtr == d._methodPtr &&
                    dd._target == d._target &&
                    dd._methodPtrAux == d._methodPtrAux)
                {
                    return true;
                }
            }
            return false;
        }
 
        private MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount, bool thisIsMultiCastAlready)
        {
            // First, allocate a new multicast delegate just like this one, i.e. same type as the this object
            MulticastDelegate result = (MulticastDelegate)InternalAllocLike(this);
 
            // Performance optimization - if this already points to a true multicast delegate,
            // copy _methodPtr and _methodPtrAux fields rather than calling into the EE to get them
            if (thisIsMultiCastAlready)
            {
                result._methodPtr = this._methodPtr;
                result._methodPtrAux = this._methodPtrAux;
            }
            else
            {
                result._methodPtr = GetMulticastInvoke();
                result._methodPtrAux = GetInvokeMethod();
            }
            result._target = result;
            result._invocationList = invocationList;
            result._invocationCount = (IntPtr)invocationCount;
 
            return result;
        }
 
        internal MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount)
        {
            return NewMulticastDelegate(invocationList, invocationCount, false);
        }
 
        internal void StoreDynamicMethod(MethodInfo dynamicMethod)
        {
            if (_invocationCount != (IntPtr)0)
            {
                Debug.Assert(!IsUnmanagedFunctionPtr(), "dynamic method and unmanaged fntptr delegate combined");
                // must be a secure/wrapper one, unwrap and save
                MulticastDelegate d = ((MulticastDelegate?)_invocationList)!;
                d._methodBase = dynamicMethod;
            }
            else
                _methodBase = dynamicMethod;
        }
 
        // This method will combine this delegate with the passed delegate
        //    to form a new delegate.
        protected sealed override Delegate CombineImpl(Delegate? follow)
        {
            if (follow is null)
                return this;
 
            // Verify that the types are the same...
            if (!InternalEqualTypes(this, follow))
                throw new ArgumentException(SR.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;
            if (!(_invocationList is object[] invocationList))
            {
                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);
            }
        }
 
        private object[] DeleteFromInvocationList(object[] invocationList, int invocationCount, int deleteIndex, int deleteCount)
        {
            Debug.Assert(_invocationList is object[]);
            object[] thisInvocationList = (object[])_invocationList;
            int allocCount = thisInvocationList.Length;
            while (allocCount / 2 >= invocationCount - deleteCount)
                allocCount /= 2;
 
            object[] newInvocationList = new object[allocCount];
 
            for (int i = 0; i < deleteIndex; i++)
                newInvocationList[i] = invocationList[i];
 
            for (int i = deleteIndex + deleteCount; i < invocationCount; i++)
                newInvocationList[i - deleteCount] = invocationList[i];
 
            return newInvocationList;
        }
 
        private static bool EqualInvocationLists(object[] a, object[] b, int start, int count)
        {
            for (int i = 0; i < count; i++)
            {
                if (!a[start + i].Equals(b[i]))
                    return false;
            }
            return true;
        }
 
        // This method currently looks backward on the invocation list
        //    for an element that has Delegate based equality with value.  (Doesn't
        //    look at the invocation list.)  If this is found we remove it from
        //    this list and return a new delegate.  If its not found a copy of the
        //    current list is returned.
        protected sealed override Delegate? RemoveImpl(Delegate value)
        {
            // There is a special case were we are removing using a delegate as
            //    the value we need to check for this case
            //
            MulticastDelegate? v = value as MulticastDelegate;
 
            if (v == null)
                return this;
            if (!(v._invocationList is object[]))
            {
                if (!(_invocationList is object[] invocationList))
                {
                    // they are both not real Multicast
                    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)
                            {
                                // Special case - only one value left, either at the beginning or the end
                                return (Delegate)invocationList[1 - i];
                            }
                            else
                            {
                                object[] list = DeleteFromInvocationList(invocationList, invocationCount, i, 1);
                                return NewMulticastDelegate(list, invocationCount - 1, true);
                            }
                        }
                    }
                }
            }
            else
            {
                if (_invocationList is object[] invocationList)
                {
                    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)
                            {
                                // Special case - no values left
                                return null;
                            }
                            else if (invocationCount - vInvocationCount == 1)
                            {
                                // Special case - only one value left, either at the beginning or the end
                                return (Delegate)invocationList[i != 0 ? 0 : invocationCount - 1];
                            }
                            else
                            {
                                object[] list = DeleteFromInvocationList(invocationList, invocationCount, i, vInvocationCount);
                                return NewMulticastDelegate(list, invocationCount - vInvocationCount, true);
                            }
                        }
                    }
                }
            }
 
            return this;
        }
 
        // This method returns the Invocation list of this multicast delegate.
        public sealed override Delegate[] GetInvocationList()
        {
            Delegate[] del;
            if (!(_invocationList is object[] invocationList))
            {
                del = new Delegate[1];
                del[0] = this;
            }
            else
            {
                // Create an array of delegate copies and each
                //    element into the array
                del = new Delegate[(int)_invocationCount];
 
                for (int i = 0; i < del.Length; i++)
                    del[i] = (Delegate)invocationList[i];
            }
            return del;
        }
 
        // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator ==(MulticastDelegate? d1, MulticastDelegate? d2)
        {
            // Test d2 first to allow branch elimination when inlined for null checks (== null)
            // so it can become a simple test
            if (d2 is null)
            {
                // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
                return (d1 is null) ? true : false;
            }
 
            return ReferenceEquals(d2, d1) ? true : d2.Equals((object?)d1);
        }
 
        // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator !=(MulticastDelegate? d1, MulticastDelegate? d2)
        {
            // Can't call the == operator as it will call object==
 
            // Test d2 first to allow branch elimination when inlined for not null checks (!= null)
            // so it can become a simple test
            if (d2 is null)
            {
                // return true/false not the test result https://github.com/dotnet/runtime/issues/4207
                return (d1 is null) ? false : true;
            }
 
            return ReferenceEquals(d2, d1) ? false : !d2.Equals(d1);
        }
 
        public sealed override int GetHashCode()
        {
            if (IsUnmanagedFunctionPtr())
                return ValueType.GetHashCodeOfPtr(_methodPtr) ^ ValueType.GetHashCodeOfPtr(_methodPtrAux);
 
            if (_invocationCount != (IntPtr)0)
            {
                if (_invocationList is Delegate t)
                {
                    // this is a wrapper delegate so we need to unwrap and check the inner one
                    return t.GetHashCode();
                }
            }
 
            if (!(_invocationList is object[] invocationList))
            {
                return base.GetHashCode();
            }
            else
            {
                int hash = 0;
                for (int i = 0; i < (int)_invocationCount; i++)
                {
                    hash = hash * 33 + invocationList[i].GetHashCode();
                }
 
                return hash;
            }
        }
 
        internal override object? GetTarget()
        {
            if (_invocationCount != (IntPtr)0)
            {
                // _invocationCount != 0 we are in one of these cases:
                // - Multicast -> return the target of the last delegate in the list
                // - Wrapper delegate -> return the target of the inner delegate
                // - unmanaged function pointer - return null
                // - virtual open delegate - return null
                if (InvocationListLogicallyNull())
                {
                    // both open virtual and ftn pointer return null for the target
                    return null;
                }
                else
                {
                    if (_invocationList is object[] invocationList)
                    {
                        int invocationCount = (int)_invocationCount;
                        return ((Delegate)invocationList[invocationCount - 1]).GetTarget();
                    }
                    else
                    {
                        if (_invocationList is Delegate receiver)
                            return receiver.GetTarget();
                    }
                }
            }
            return base.GetTarget();
        }
 
        protected override MethodInfo GetMethodImpl()
        {
            if (_invocationCount != (IntPtr)0 && _invocationList != null)
            {
                // multicast case
                if (_invocationList is object[] invocationList)
                {
                    int index = (int)_invocationCount - 1;
                    return ((Delegate)invocationList[index]).Method;
                }
 
                if (_invocationList is MulticastDelegate innerDelegate)
                {
                    // must be a wrapper delegate
                    return innerDelegate.GetMethodImpl();
                }
            }
            else if (IsUnmanagedFunctionPtr())
            {
                // we handle unmanaged function pointers here because the generic ones (used for WinRT) would otherwise
                // be treated as open delegates by the base implementation, resulting in failure to get the MethodInfo
                if ((_methodBase == null) || !(_methodBase is MethodInfo))
                {
                    IRuntimeMethodInfo method = FindMethodHandle();
                    RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(method);
 
                    // need a proper declaring type instance method on a generic type
                    if (RuntimeTypeHandle.IsGenericTypeDefinition(declaringType) || RuntimeTypeHandle.HasInstantiation(declaringType))
                    {
                        // we are returning the 'Invoke' method of this delegate so use this.GetType() for the exact type
                        RuntimeType reflectedType = (RuntimeType)GetType();
                        declaringType = reflectedType;
                    }
                    _methodBase = (MethodInfo)RuntimeType.GetMethodBase(declaringType, method)!;
                }
                return (MethodInfo)_methodBase;
            }
 
            // Otherwise, must be an inner delegate of a wrapper delegate of an open virtual method. In that case, call base implementation
            return base.GetMethodImpl();
        }
 
        // this should help inlining
        [DoesNotReturn]
        [System.Diagnostics.DebuggerNonUserCode]
        private static void ThrowNullThisInDelegateToInstance() =>
            throw new ArgumentException(SR.Arg_DlgtNullInst);
 
#pragma warning disable IDE0060
        [System.Diagnostics.DebuggerNonUserCode]
        private void CtorClosed(object target, IntPtr methodPtr)
        {
            if (target == null)
                ThrowNullThisInDelegateToInstance();
            this._target = target;
            this._methodPtr = methodPtr;
        }
 
        [System.Diagnostics.DebuggerNonUserCode]
        private void CtorClosedStatic(object target, IntPtr methodPtr)
        {
            this._target = target;
            this._methodPtr = methodPtr;
        }
 
        [System.Diagnostics.DebuggerNonUserCode]
        private void CtorRTClosed(object target, IntPtr methodPtr)
        {
            this._target = target;
            this._methodPtr = AdjustTarget(target, methodPtr);
        }
 
        [System.Diagnostics.DebuggerNonUserCode]
        private void CtorOpened(object target, IntPtr methodPtr, IntPtr shuffleThunk)
        {
            this._target = this;
            this._methodPtr = shuffleThunk;
            this._methodPtrAux = methodPtr;
        }
 
        [System.Diagnostics.DebuggerNonUserCode]
        private void CtorVirtualDispatch(object target, IntPtr methodPtr, IntPtr shuffleThunk)
        {
            this._target = this;
            this._methodPtr = shuffleThunk;
            this._methodPtrAux = GetCallStub(methodPtr);
        }
 
        [System.Diagnostics.DebuggerNonUserCode]
        private void CtorCollectibleClosedStatic(object target, IntPtr methodPtr, IntPtr gchandle)
        {
            this._target = target;
            this._methodPtr = methodPtr;
            this._methodBase = System.Runtime.InteropServices.GCHandle.InternalGet(gchandle);
        }
 
        [System.Diagnostics.DebuggerNonUserCode]
        private void CtorCollectibleOpened(object target, IntPtr methodPtr, IntPtr shuffleThunk, IntPtr gchandle)
        {
            this._target = this;
            this._methodPtr = shuffleThunk;
            this._methodPtrAux = methodPtr;
            this._methodBase = System.Runtime.InteropServices.GCHandle.InternalGet(gchandle);
        }
 
        [System.Diagnostics.DebuggerNonUserCode]
        private void CtorCollectibleVirtualDispatch(object target, IntPtr methodPtr, IntPtr shuffleThunk, IntPtr gchandle)
        {
            this._target = this;
            this._methodPtr = shuffleThunk;
            this._methodPtrAux = GetCallStub(methodPtr);
            this._methodBase = System.Runtime.InteropServices.GCHandle.InternalGet(gchandle);
        }
#pragma warning restore IDE0060
    }
}
MulticaseDelegate三个重要的非公有字段
targetObject当委托对象包装一个静态方法时,这个字段为null,当委托对象包装一个实例方法时,这个字段就是要回调方法操作的对象,这个字段要指出传给实例参数的隐形字段this
methodptrInptr内部的整数值
invocationlistObject构造委托链时引用一个委托数组

 

2.使用委托

委托的使用需要以下步骤:

定义委托

delegate double ParocessDelegate(double param1,double param2);

委托的定义非常类似于函数,但不带函数体,且要使用delegate关键字。委托定义需要指明委托名称以及一个返回类型和一个参数列表

声明委托类型的变量

ProcessDelegate process;

定义了委托后,就可以声明一个该委托类型的变量

初始化委托变量

process =new ProcessDelegate(Multiply);

初始化委托变量时要把一个函数(此处Multiply为一个函数的名称)引用赋给委托变量,此函数需要具有与委托相同的返回类型和参数列表。c#使用上述略显古怪的语法,使用new关键字创建一个新的委托,参数为
要引用所需的函数,这是委托赋值的一个独特语法,函数名称是不带括号的

还可以用另一种略微简单的语法

process = Muiltiply;

有了引用函数的委托变量之后,我们就可以用委托变量调用Muiltiply函数;也可以把委托变量传递给其他函数

process (param1,param2);

namespace Delegate
{

        public delegate int Call(int num1, int num2);//第一步:定义委托类型
        class SimpleMath
        {
            // 乘法方法
            public int Multiply(int num1, int num2)
            {
                return num1 * num2;
            }

            // 除法方法
            public int Divide(int num1, int num2)
            {
                return num1 / num2;
            }
        }
    }
    class Test
    {
        static void Main(string[] args)
        {
            Call objCall;//第二步:声明委托变量
            // Math 类的对象
            SimpleMath objMath = new SimpleMath(); 
            // 第三步:初始化委托变量,将方法与委托关联起来
            objCall = new Call(objMath.Multiply);

           
            objCall += objMath.Divide;//向委托增加一个方法
            //objCall -=  objMath.Divide;//向委托减去一个方法

            // 调用委托实例,先执行objMath.Multiply,然后执行objMath.Divide
            int result = objCall(5, 3);
            System.Console.WriteLine("结果为 {0}", result);
            Console.ReadKey();
        }
    }

注意事项:

  • 委托可以调用多个方法,即一个委托变量可以引用多个函数,称为多路广播
  • 可以使用+=和-=运算符实现方法的增加和减少
  • 无返回值的委托,引用了多少个方法就会执行多少个方法。有返回值的委托同样会执行多个引用的方法,但返回的值是最后一个方法的返回值

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值