Delegate resolution in C,

Source: Internet
Author: User

Delegate resolution in C,

When talking about the basic features of C #, "delegation" is a feature that has to be understood and analyzed in depth. When talking about "delegation", most beginners will think of "passing methods as method parameters". Many times, they only know simple definitions, this is mainly because "delegation" is difficult to understand than other features. In this description, simple comments and calls of the Delegate will not be the focus.

"Delegate" does not need to directly define an action to be executed, but to "include" this behavior in an object in some way. This object can be used as any other object. In this object, you can perform encapsulated operations. You can choose to regard delegation as an interface that defines a method, and the delegated instance as an object that implements that interface.

In the definition of "delegation", we can see that "delegation and method" have similar design concepts compared with "interfaces and classes, the background is derived from the "open-closed principle" in the "design principle" and the "open-closed" principle: software entities (classes, modules, functions, etc.) should be extensible, but cannot be modified. In other words, we may better understand that "expansion is open and changes are closed". In the face of new requirements, program changes are implemented by adding new code, instead of changing the existing code.

In C #, the delegate is defined by the delegate keyword, and the new operator is used to construct the delegate instance, use the traditional method call syntax to call the function back and forth (only replace the method name with a variable that references the delegate object ). In C #, the delegate is compiled into a class during compilation. A description of delegation: A delegate is a class that defines the type of a method, so that the method can be passed as a parameter of another method. The delegate class can be defined either in a type or globally. Because delegation is a class, delegation can be defined wherever a class can be defined.

Next, let's take a look at the composition of the "delegate" and the conditions to be met:

1. Declare the delegate type.

2. A method must contain the code to be executed.

3. You must create a delegated instance.

4. the delegated instance must be called.

Next, let's take a rough look at the four conditions mentioned above:

The delegate type is actually a list of parameter types and the return type. Specifies the actions that can be represented by a type of instance. When calling a delegated instance, you must ensure that the parameters used are completely matched and the return value can be used in a specified way. The creation of a delegated instance depends on whether the instance method or static method is used for the operation. (if the operation is a static method, you can specify the type name. If the operation is an instance method, you must first create a type of instance ). For a delegate call, you can directly call the delegate instance method to complete the corresponding operation.

The definition and composition of the "delegate" are discussed above. Next, let's take a look at how to bind the method to the "delegate" and how to merge and delete the delegate.

You can assign multiple methods to the same delegate. The delegated instance actually has an operation list associated with it. The System. Delegate type provides two static methods: Combine () and Remove (), which are used to Delegate the addition and deletion of instances. However, in our actual development, many operators-= and + = are used.

In FCL, all Delegate types are derived from MulticastDelegate, which is of the System. MulticastDelegate type.

Let's take a look at the underlying implementation code of the Combine () method:

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

The above two methods are of the System. Delegate type, and the CombineImpl method is rewritten in 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);            }         } 

Let's take a look at the underlying implementation code of the Remove () method. The RemoveAll and Remove methods are of the System. Delegate type, and the CombineImpl method is rewritten in 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;        } 

In the above Code, we learned how to bind and delete a delegate instance at the. NET underlying layer.

When a delegated instance is called, all operations are executed sequentially. If a call has a non-void return type, the return value of the call is the return value of the last operation. If any operation in the call list throws an exception, subsequent operations are blocked.

As mentioned above, non-void instance calls appear in the delegate list. If multiple non-void calls exist in the delegate instance and you need to obtain the return values of all the delegate instances, what should you do, in. NET red provides a method GetInvocationList () for obtaining the delegate linked list.

Next, let's take a look at the underlying code of 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;         }

After obtaining the delegated instance list, you can obtain the return values of each delegated instance in sequence by means of loop iteration.

Next, let's take a look at the underlying implementation code of the Property 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;         }

The above is the definition in the System. Delegate class. Next let's take a look at the MulticastDelegate rewrite:

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

The preceding sections describe how to create and use a delegate based on the relevant definition of the Delegate and the instructions on some delegate operation methods, for most developers, it is relatively simple, because Microsoft is constantly improving and modifying the C # syntax, greatly simplifying the corresponding operations. However, it is precisely because of the large encapsulation at the application layer that the complexity of features at the underlying layer will gradually increase.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.