summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/DelegateSerializationHolder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/DelegateSerializationHolder.cs')
-rw-r--r--src/mscorlib/src/System/DelegateSerializationHolder.cs299
1 files changed, 299 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/DelegateSerializationHolder.cs b/src/mscorlib/src/System/DelegateSerializationHolder.cs
new file mode 100644
index 0000000000..a6280333db
--- /dev/null
+++ b/src/mscorlib/src/System/DelegateSerializationHolder.cs
@@ -0,0 +1,299 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+using System;
+using System.Reflection;
+using System.Runtime.Remoting;
+using System.Runtime.Serialization;
+using System.Security.Permissions;
+using System.Globalization;
+using System.Diagnostics.Contracts;
+
+namespace System
+{
+ [Serializable]
+ internal sealed class DelegateSerializationHolder : IObjectReference, ISerializable
+ {
+ #region Static Members
+ [System.Security.SecurityCritical] // auto-generated
+ internal static DelegateEntry GetDelegateSerializationInfo(
+ SerializationInfo info, Type delegateType, Object target, MethodInfo method, int targetIndex)
+ {
+ // Used for MulticastDelegate
+
+ if (method == null)
+ throw new ArgumentNullException("method");
+ Contract.EndContractBlock();
+
+ if (!method.IsPublic || (method.DeclaringType != null && !method.DeclaringType.IsVisible))
+ new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Demand();
+
+ Type c = delegateType.BaseType;
+
+ if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDelegate"),"type");
+
+ if (method.DeclaringType == null)
+ throw new NotSupportedException(Environment.GetResourceString("NotSupported_GlobalMethodSerialization"));
+
+ DelegateEntry de = new DelegateEntry(delegateType.FullName, delegateType.Module.Assembly.FullName, target,
+ method.ReflectedType.Module.Assembly.FullName, method.ReflectedType.FullName, method.Name);
+
+ if (info.MemberCount == 0)
+ {
+ info.SetType(typeof(DelegateSerializationHolder));
+ info.AddValue("Delegate",de,typeof(DelegateEntry));
+ }
+
+ // target can be an object so it needs to be added to the info, or else a fixup is needed
+ // when deserializing, and the fixup will occur too late. If it is added directly to the
+ // info then the rules of deserialization will guarantee that it will be available when
+ // needed
+
+ if (target != null)
+ {
+ String targetName = "target" + targetIndex;
+ info.AddValue(targetName, de.target);
+ de.target = targetName;
+ }
+
+ // Due to a number of additions (delegate signature binding relaxation, delegates with open this or closed over the
+ // first parameter and delegates over generic methods) we need to send a deal more information than previously. We can
+ // get this by serializing the target MethodInfo. We still need to send the same information as before though (the
+ // DelegateEntry above) for backwards compatibility. And we want to send the MethodInfo (which is serialized via an
+ // ISerializable holder) as a top-level child of the info for the same reason as the target above -- we wouldn't have an
+ // order of deserialization guarantee otherwise.
+ String methodInfoName = "method" + targetIndex;
+ info.AddValue(methodInfoName, method);
+
+ return de;
+ }
+ #endregion
+
+ #region Definitions
+ [Serializable]
+ internal class DelegateEntry
+ {
+ #region Internal Data Members
+ internal String type;
+ internal String assembly;
+ internal Object target;
+ internal String targetTypeAssembly;
+ internal String targetTypeName;
+ internal String methodName;
+ internal DelegateEntry delegateEntry;
+ #endregion
+
+ #region Constructor
+ internal DelegateEntry(
+ String type, String assembly, Object target, String targetTypeAssembly, String targetTypeName, String methodName)
+ {
+ this.type = type;
+ this.assembly = assembly;
+ this.target = target;
+ this.targetTypeAssembly = targetTypeAssembly;
+ this.targetTypeName = targetTypeName;
+ this.methodName = methodName;
+ }
+ #endregion
+
+ #region Internal Members
+ internal DelegateEntry Entry
+ {
+ get { return delegateEntry; }
+ set { delegateEntry = value; }
+ }
+ #endregion
+ }
+
+ #endregion
+
+ #region Private Data Members
+ private DelegateEntry m_delegateEntry;
+ private MethodInfo[] m_methods;
+ #endregion
+
+ #region Constructor
+ [System.Security.SecurityCritical] // auto-generated
+ private DelegateSerializationHolder(SerializationInfo info, StreamingContext context)
+ {
+ if (info == null)
+ throw new ArgumentNullException("info");
+ Contract.EndContractBlock();
+
+ bool bNewWire = true;
+
+ try
+ {
+ m_delegateEntry = (DelegateEntry)info.GetValue("Delegate", typeof(DelegateEntry));
+ }
+ catch
+ {
+ // Old wire format
+ m_delegateEntry = OldDelegateWireFormat(info, context);
+ bNewWire = false;
+ }
+
+ if (bNewWire)
+ {
+ // retrieve the targets
+ DelegateEntry deiter = m_delegateEntry;
+ int count = 0;
+ while (deiter != null)
+ {
+ if (deiter.target != null)
+ {
+ string stringTarget = deiter.target as string; //need test to pass older wire format
+ if (stringTarget != null)
+ deiter.target = info.GetValue(stringTarget, typeof(Object));
+ }
+ count++;
+ deiter = deiter.delegateEntry;
+ }
+
+ // If the sender is as recent as us they'll have provided MethodInfos for each delegate. Look for these and pack
+ // them into an ordered array if present.
+ MethodInfo[] methods = new MethodInfo[count];
+ int i;
+ for (i = 0; i < count; i++)
+ {
+ String methodInfoName = "method" + i;
+ methods[i] = (MethodInfo)info.GetValueNoThrow(methodInfoName, typeof(MethodInfo));
+ if (methods[i] == null)
+ break;
+ }
+
+ // If we got the info then make the array available for deserialization.
+ if (i == count)
+ m_methods = methods;
+ }
+ }
+ #endregion
+
+ #region Private Members
+ private void ThrowInsufficientState(string field)
+ {
+ throw new SerializationException(
+ Environment.GetResourceString("Serialization_InsufficientDeserializationState", field));
+ }
+
+ private DelegateEntry OldDelegateWireFormat(SerializationInfo info, StreamingContext context)
+ {
+ if (info == null)
+ throw new ArgumentNullException("info");
+ Contract.EndContractBlock();
+
+ String delegateType = info.GetString("DelegateType");
+ String delegateAssembly = info.GetString("DelegateAssembly");
+ Object target = info.GetValue("Target", typeof(Object));
+ String targetTypeAssembly = info.GetString("TargetTypeAssembly");
+ String targetTypeName = info.GetString("TargetTypeName");
+ String methodName = info.GetString("MethodName");
+
+ return new DelegateEntry(delegateType, delegateAssembly, target, targetTypeAssembly, targetTypeName, methodName);
+ }
+
+ [System.Security.SecurityCritical]
+ private Delegate GetDelegate(DelegateEntry de, int index)
+ {
+ Delegate d;
+
+ try
+ {
+ if (de.methodName == null || de.methodName.Length == 0)
+ ThrowInsufficientState("MethodName");
+
+ if (de.assembly == null || de.assembly.Length == 0)
+ ThrowInsufficientState("DelegateAssembly");
+
+ if (de.targetTypeName == null || de.targetTypeName.Length == 0)
+ ThrowInsufficientState("TargetTypeName");
+
+ // We cannot use Type.GetType directly, because of AppCompat - assembly names starting with '[' would fail to load.
+ RuntimeType type = (RuntimeType)Assembly.GetType_Compat(de.assembly, de.type);
+ RuntimeType targetType = (RuntimeType)Assembly.GetType_Compat(de.targetTypeAssembly, de.targetTypeName);
+
+ // If we received the new style delegate encoding we already have the target MethodInfo in hand.
+ if (m_methods != null)
+ {
+#if FEATURE_REMOTING
+ Object target = de.target != null ? RemotingServices.CheckCast(de.target, targetType) : null;
+#else
+ if(de.target != null && !targetType.IsInstanceOfType(de.target))
+ throw new InvalidCastException();
+ Object target=de.target;
+#endif
+ d = Delegate.CreateDelegateNoSecurityCheck(type, target, m_methods[index]);
+ }
+ else
+ {
+ if (de.target != null)
+#if FEATURE_REMOTING
+ d = Delegate.CreateDelegate(type, RemotingServices.CheckCast(de.target, targetType), de.methodName);
+#else
+ {
+ if(!targetType.IsInstanceOfType(de.target))
+ throw new InvalidCastException();
+ d = Delegate.CreateDelegate(type, de.target, de.methodName);
+ }
+#endif
+ else
+ d = Delegate.CreateDelegate(type, targetType, de.methodName);
+ }
+
+ if ((d.Method != null && !d.Method.IsPublic) || (d.Method.DeclaringType != null && !d.Method.DeclaringType.IsVisible))
+ new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Demand();
+ }
+ catch (Exception e)
+ {
+ if (e is SerializationException)
+ throw e;
+
+ throw new SerializationException(e.Message, e);
+ }
+
+ return d;
+ }
+ #endregion
+
+ #region IObjectReference
+ [System.Security.SecurityCritical] // auto-generated
+ public Object GetRealObject(StreamingContext context)
+ {
+ int count = 0;
+ for (DelegateEntry de = m_delegateEntry; de != null; de = de.Entry)
+ count++;
+
+ int maxindex = count - 1;
+
+ if (count == 1)
+ {
+ return GetDelegate(m_delegateEntry, 0);
+ }
+ else
+ {
+ object[] invocationList = new object[count];
+
+ for (DelegateEntry de = m_delegateEntry; de != null; de = de.Entry)
+ {
+ // Be careful to match the index we pass to GetDelegate (used to look up extra information for each delegate) to
+ // the order we process the entries: we're actually looking at them in reverse order.
+ --count;
+ invocationList[count] = GetDelegate(de, maxindex - count);
+ }
+ return ((MulticastDelegate)invocationList[0]).NewMulticastDelegate(invocationList, invocationList.Length);
+ }
+ }
+ #endregion
+
+ #region ISerializable
+ [System.Security.SecurityCritical] // auto-generated
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ throw new NotSupportedException(Environment.GetResourceString("NotSupported_DelegateSerHolderSerial"));
+ }
+ #endregion
+ }
+}