C#中的委托解析

   
谈及到C#的基本特点,“委托”是不得不去理解和深入剖析的三个表征。对于绝超越2/4刚入门的程序员谈到“委托”时,都会想到“将艺术作为艺术的参数实行传递”,很多时候都只是知道简单的定义,首假如因为“委托”在领略上有较其余特色相比较难的地方。在这次表明中,不会将委托的粗略表明和调用作为重点。

   
“委托”不必要一向定义一个要推行的作为,而是将这一个行为用某种格局“包括”在一个目标中。那些目的足以像其余任何对象那样采取。在该对象中,能够推行封装的操作。能够选拔将委托看作之定义了1个方法的接口,将委托的实例看作完结了12分接口的目的。

   
在“委托”的连带定义中,我们能够不难看出,“委托与情势“绝相比于“接口与类”有着设计意见上的貌似部分,发生的背景源于”设计基准“中的”开放-封闭原则“,”开放-封闭“原则:是说软件实体(类,模块,函数等等)应该能够扩张,不过不可修改。换一种说法只怕更好的知晓”对于增添是开放的,对于改变是查封的“,面对新的必要,对于程序的转移是透过扩展新的代码举行的,而不是改变现有的代码。

 
 在C#中央委员托用delegate关键字定义,使用new操作符构造委托实例,采纳守旧的章程调用语法来回调函数(只是要用引用了寄托对象的贰个变量代替方法名)。在C#中,委托在编写翻译的时候会被编写翻译成类。对于信托的二个认证:委托是二个类,它定义了法子的种类,使得能够将艺术当作另叁个主意的参数来进展传递。委托类既可嵌套在一个连串中定义,也能够在大局范围钦点义。由于委托是类,凡是足以定义类的地方,都足以定义委托。

  接下去我们来看一下”委托“的组合,需求满意的口径:

     1.证明委托类型。

     2.亟须有1个措施包罗了要实施的代码。

     3.要求创立贰个委托实例。

     4.亟须调用委托实例。

    接下去大约的询问一下地点所提议的4项标准:

   
 委托类型实际上只是参数类型的一个列表以及重返类型。规定了类其余实例能代表的操作。在调用二个寄托实例的时候,必须有限支撑使用的参数完全合营,而且能以钦定的主意使用重临值。对于信托实例的创导,取决于操作使用实例方法依然静态方法(倘诺操作是静态方法,内定项目名称就足以,假若是操作实例方法,须要先创设项指标实例)。对于信托的调用,能够一直调用委托的实例的不二法门就足以成功对应的操作。

   
以上谈及了”委托“的概念和整合,接下去大家来打听一下怎样将艺术绑定到”委托“上,以及委托的合并和删除。

   
能够将三个格局赋给同三个委托,委托实例实际有二个操作列表与之提到。在System.Delegate类型中提供了八个静态方法Combine()和Remove()负责信托实例的新增和删除操作。不过在大家的实际上支出中,较多的使用-=和+=操作符。

 
在FCL中,全部的委托项目都派生自MulticastDelegate,该品种在System.MulticastDelegate类型中。

   具体来看一下Combine()方法的尾部达成代码:

 [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()方法的平底完结代码,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底层是怎么样贯彻委托实例的绑定和删除绑定。

 
在调用委托实例时,全体的操作都是逐一执行的。如若调用具有1个非void的回来类型,则调用的重返值是最后一个操作的重返值。要是调用列表中任何操作抛出至极,都会阻止实施后续的操作。

 
 在上边提到了委托列表中冒出非void实例调用,假诺委托实例中出现多少个非void调用,并且须求获得具有的嘱托实例的重回值结果,那么应该怎么样操作,在.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; 
        }

 
 当获取到委托实例列表后,可使用循环迭代的方式,依次获得每个委托实例的再次来到值。

   再来驾驭贰性格能Method,具体看一下此属性的底部完成代码:

       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(); 
        }

 
 以上是对信托的有关定义,以及有关委托的一部分操作方法的辨证,没有现实提出什么去创设和动用委托,因为委托的粗略成立和一般采用,对于多数开发者来说是相对较为简单的,因为微软在持续的对C#的语法举办升级和改动,相当的大的简化了相应的操作。可是辛亏出于在应用层做了较大的包裹,那也会导致天性在尾部的复杂度稳步的叠加。

相关文章