The Labs \ Source Viewer \ SSCLI \ System \ DelegateEntry

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. using System;
  16. using System.Reflection;
  17. using System.Runtime.Remoting;
  18. using System.Runtime.Remoting.Messaging;
  19. using System.Runtime.Serialization;
  20. using System.Security.Permissions;
  21. using System.Globalization;
  22. namespace System
  23. {
  24.     [Serializable()]
  25.     internal sealed class DelegateSerializationHolder : IObjectReference, ISerializable
  26.     {
  27.         #region Static Members
  28.         static internal DelegateEntry GetDelegateSerializationInfo(SerializationInfo info, Type delegateType, object target, MethodInfo method, int targetIndex)
  29.         {
  30.             // Used for MulticastDelegate
  31.            
  32.             if (method == null)
  33.                 throw new ArgumentNullException("method");
  34.            
  35.             if (!method.IsPublic || (method.DeclaringType != null && !method.DeclaringType.IsVisible))
  36.                 new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Demand();
  37.            
  38.             Type c = delegateType.BaseType;
  39.            
  40.             if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
  41.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDelegate"), "type");
  42.            
  43.             if (method.DeclaringType == null)
  44.                 throw new NotSupportedException(Environment.GetResourceString("NotSupported_GlobalMethodSerialization"));
  45.            
  46.             DelegateEntry de = new DelegateEntry(delegateType.FullName, delegateType.Module.Assembly.FullName, target, method.ReflectedType.Module.Assembly.FullName, method.ReflectedType.FullName, method.Name);
  47.            
  48.             if (info.MemberCount == 0) {
  49.                 info.SetType(typeof(DelegateSerializationHolder));
  50.                 info.AddValue("Delegate", de, typeof(DelegateEntry));
  51.             }
  52.            
  53.             // target can be an object so it needs to be added to the info, or else a fixup is needed
  54.             // when deserializing, and the fixup will occur too late. If it is added directly to the
  55.             // info then the rules of deserialization will guarantee that it will be available when
  56.             // needed
  57.            
  58.             if (target != null) {
  59.                 string targetName = "target" + targetIndex;
  60.                 info.AddValue(targetName, de.target);
  61.                 de.target = targetName;
  62.             }
  63.            
  64.             // Due to a number of additions (delegate signature binding relaxation, delegates with open this or closed over the
  65.             // first parameter and delegates over generic methods) we need to send a deal more information than previously. We can
  66.             // get this by serializing the target MethodInfo. We still need to send the same information as before though (the
  67.             // DelegateEntry above) for backwards compatibility. And we want to send the MethodInfo (which is serialized via an
  68.             // ISerializable holder) as a top-level child of the info for the same reason as the target above -- we wouldn't have an
  69.             // order of deserialization guarantee otherwise.
  70.             string methodInfoName = "method" + targetIndex;
  71.             info.AddValue(methodInfoName, method);
  72.            
  73.             return de;
  74.         }
  75.         #endregion
  76.        
  77.         #region Definitions
  78.         [Serializable()]
  79.         internal class DelegateEntry
  80.         {
  81.             #region Internal Data Members
  82.             internal string type;
  83.             internal string assembly;
  84.             internal object target;
  85.             internal string targetTypeAssembly;
  86.             internal string targetTypeName;
  87.             internal string methodName;
  88.             internal DelegateEntry delegateEntry;
  89.             #endregion
  90.            
  91.             #region Constructor
  92.             internal DelegateEntry(string type, string assembly, object target, string targetTypeAssembly, string targetTypeName, string methodName)
  93.             {
  94.                 this.type = type;
  95.                 this.assembly = assembly;
  96.                 this.target = target;
  97.                 this.targetTypeAssembly = targetTypeAssembly;
  98.                 this.targetTypeName = targetTypeName;
  99.                 this.methodName = methodName;
  100.             }
  101.             #endregion
  102.            
  103.             #region Internal Members
  104.             internal DelegateEntry Entry {
  105.                 get { return delegateEntry; }
  106.                 set { delegateEntry = value; }
  107.             }
  108.             #endregion
  109.         }
  110.        
  111.         #endregion
  112.        
  113.         #region Private Data Members
  114.         private DelegateEntry m_delegateEntry;
  115.         private MethodInfo[] m_methods;
  116.         #endregion
  117.        
  118.         #region Constructor
  119.         private DelegateSerializationHolder(SerializationInfo info, StreamingContext context)
  120.         {
  121.             if (info == null)
  122.                 throw new ArgumentNullException("info");
  123.            
  124.             bool bNewWire = true;
  125.            
  126.             try {
  127.                 m_delegateEntry = (DelegateEntry)info.GetValue("Delegate", typeof(DelegateEntry));
  128.             }
  129.             catch {
  130.                 // Old wire format
  131.                 m_delegateEntry = OldDelegateWireFormat(info, context);
  132.                 bNewWire = false;
  133.             }
  134.            
  135.             if (bNewWire) {
  136.                 // retrieve the targets
  137.                 DelegateEntry deiter = m_delegateEntry;
  138.                 int count = 0;
  139.                 while (deiter != null) {
  140.                     if (deiter.target != null) {
  141.                         string stringTarget = deiter.target as string;
  142.                         //need test to pass older wire format
  143.                         if (stringTarget != null)
  144.                             deiter.target = info.GetValue(stringTarget, typeof(object));
  145.                     }
  146.                     count++;
  147.                     deiter = deiter.delegateEntry;
  148.                 }
  149.                
  150.                 // If the sender is as recent as us they'll have provided MethodInfos for each delegate. Look for these and pack
  151.                 // them into an ordered array if present.
  152.                 MethodInfo[] methods = new MethodInfo[count];
  153.                 int i;
  154.                 for (i = 0; i < count; i++) {
  155.                     string methodInfoName = "method" + i;
  156.                     methods[i] = (MethodInfo)info.GetValueNoThrow(methodInfoName, typeof(MethodInfo));
  157.                     if (methods[i] == null)
  158.                         break;
  159.                 }
  160.                
  161.                 // If we got the info then make the array available for deserialization.
  162.                 if (i == count)
  163.                     m_methods = methods;
  164.             }
  165.         }
  166.         #endregion
  167.        
  168.         #region Private Members
  169.         private void ThrowInsufficientState(string field)
  170.         {
  171.             throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_InsufficientDeserializationState"), field));
  172.         }
  173.        
  174.         private DelegateEntry OldDelegateWireFormat(SerializationInfo info, StreamingContext context)
  175.         {
  176.             if (info == null)
  177.                 throw new ArgumentNullException("info");
  178.            
  179.             string delegateType = info.GetString("DelegateType");
  180.             string delegateAssembly = info.GetString("DelegateAssembly");
  181.             object target = info.GetValue("Target", typeof(object));
  182.             string targetTypeAssembly = info.GetString("TargetTypeAssembly");
  183.             string targetTypeName = info.GetString("TargetTypeName");
  184.             string methodName = info.GetString("MethodName");
  185.            
  186.             return new DelegateEntry(delegateType, delegateAssembly, target, targetTypeAssembly, targetTypeName, methodName);
  187.         }
  188.        
  189.         private Delegate GetDelegate(DelegateEntry de, int index)
  190.         {
  191.             Delegate d;
  192.            
  193.             try {
  194.                 if (de.methodName == null || de.methodName.Length == 0)
  195.                     ThrowInsufficientState("MethodName");
  196.                
  197.                 if (de.assembly == null || de.assembly.Length == 0)
  198.                     ThrowInsufficientState("DelegateAssembly");
  199.                
  200.                 if (de.targetTypeName == null || de.targetTypeName.Length == 0)
  201.                     ThrowInsufficientState("TargetTypeName");
  202.                
  203.                 Type type = Assembly.Load(de.assembly).GetType(de.type, true, false);
  204.                 Type targetType = Assembly.Load(de.targetTypeAssembly).GetType(de.targetTypeName, true, false);
  205.                
  206.                 // If we received the new style delegate encoding we already have the target MethodInfo in hand.
  207.                 if (m_methods != null) {
  208.                     object target = de.target != null ? RemotingServices.CheckCast(de.target, targetType) : null;
  209.                     d = Delegate.InternalCreateDelegate(type, target, m_methods[index]);
  210.                 }
  211.                 else {
  212.                     if (de.target != null)
  213.                         d = Delegate.CreateDelegate(type, RemotingServices.CheckCast(de.target, targetType), de.methodName);
  214.                     else
  215.                         d = Delegate.CreateDelegate(type, targetType, de.methodName);
  216.                 }
  217.                
  218.                 if ((d.Method != null && !d.Method.IsPublic) || (d.Method.DeclaringType != null && !d.Method.DeclaringType.IsVisible))
  219.                     new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Demand();
  220.             }
  221.             catch (Exception e) {
  222.                 if (e is SerializationException)
  223.                     throw e;
  224.                
  225.                 throw new SerializationException(e.Message, e);
  226.             }
  227.             catch {
  228.                 throw new SerializationException();
  229.             }
  230.            
  231.             return d;
  232.         }
  233.         #endregion
  234.        
  235.         #region IObjectReference
  236.         public object GetRealObject(StreamingContext context)
  237.         {
  238.             int count = 0;
  239.             for (DelegateEntry de = m_delegateEntry; de != null; de = de.Entry)
  240.                 count++;
  241.            
  242.             int maxindex = count - 1;
  243.            
  244.             if (count == 1) {
  245.                 return GetDelegate(m_delegateEntry, 0);
  246.             }
  247.             else {
  248.                 object[] invocationList = new object[count];
  249.                
  250.                 for (DelegateEntry de = m_delegateEntry; de != null; de = de.Entry) {
  251.                     // Be careful to match the index we pass to GetDelegate (used to look up extra information for each delegate) to
  252.                     // the order we process the entries: we're actually looking at them in reverse order.
  253.                     --count;
  254.                     invocationList[count] = GetDelegate(de, maxindex - count);
  255.                 }
  256.                 return ((MulticastDelegate)invocationList[0]).NewMulticastDelegate(invocationList, invocationList.Length);
  257.             }
  258.         }
  259.         #endregion
  260.        
  261.         #region ISerializable
  262.         public void GetObjectData(SerializationInfo info, StreamingContext context)
  263.         {
  264.             throw new NotSupportedException(Environment.GetResourceString("NotSupported_DelegateSerHolderSerial"));
  265.         }
  266.         #endregion
  267.     }
  268. }

Developer Fusion