The Labs \ Source Viewer \ SSCLI \ System.Runtime.Serialization \ FormatterServices

  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. /*============================================================
  16. **
  17. ** Class: FormatterServices
  18. **
  19. **
  20. ** Purpose: Provides some static methods to aid with the implementation
  21. **          of a Formatter for Serialization.
  22. **
  23. **
  24. ============================================================*/
  25. namespace System.Runtime.Serialization
  26. {
  27.    
  28.     using System;
  29.     using System.Reflection;
  30.     using System.Reflection.Cache;
  31.     using System.Collections;
  32.     using System.Collections.Generic;
  33.     using System.Security;
  34.     using System.Security.Permissions;
  35.     using System.Runtime.Serialization.Formatters;
  36.     using System.Runtime.Remoting;
  37.     using System.Runtime.CompilerServices;
  38.     using System.Threading;
  39.     using StackCrawlMark = System.Threading.StackCrawlMark;
  40.     using System.IO;
  41.     using System.Text;
  42.     using System.Globalization;
  43.    
  44.     [System.Runtime.InteropServices.ComVisible(true)]
  45.     public sealed class FormatterServices
  46.     {
  47.         static internal Dictionary<MemberHolder, MemberInfo[]> m_MemberInfoTable = new Dictionary<MemberHolder, MemberInfo[]>(32);
  48.        
  49.         private static object s_FormatterServicesSyncObject = null;
  50.        
  51.         private static object formatterServicesSyncObject {
  52.             get {
  53.                 if (s_FormatterServicesSyncObject == null) {
  54.                     object o = new object();
  55.                     Interlocked.CompareExchange(ref s_FormatterServicesSyncObject, o, null);
  56.                 }
  57.                 return s_FormatterServicesSyncObject;
  58.             }
  59.         }
  60.        
  61.         private FormatterServices()
  62.         {
  63.             throw new NotSupportedException();
  64.         }
  65.        
  66.         private static MemberInfo[] GetSerializableMembers(RuntimeType type)
  67.         {
  68.             // get the list of all fields
  69.             FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  70.             int countProper = 0;
  71.             for (int i = 0; i < fields.Length; i++) {
  72.                 if ((fields[i].Attributes & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized)
  73.                     continue;
  74.                 countProper++;
  75.             }
  76.             if (countProper != fields.Length) {
  77.                 FieldInfo[] properFields = new FieldInfo[countProper];
  78.                 countProper = 0;
  79.                 for (int i = 0; i < fields.Length; i++) {
  80.                     if ((fields[i].Attributes & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized)
  81.                         continue;
  82.                     properFields[countProper] = fields[i];
  83.                     countProper++;
  84.                 }
  85.                 return properFields;
  86.             }
  87.             else
  88.                 return fields;
  89.         }
  90.        
  91.         private static bool CheckSerializable(RuntimeType type)
  92.         {
  93.             if (type.IsSerializable) {
  94.                 return true;
  95.             }
  96.             return false;
  97.         }
  98.        
  99.         private static MemberInfo[] InternalGetSerializableMembers(RuntimeType type)
  100.         {
  101.             ArrayList allMembers = null;
  102.             MemberInfo[] typeMembers;
  103.             FieldInfo[] typeFields;
  104.             RuntimeType parentType;
  105.            
  106.             BCLDebug.Assert(type != null, "[GetAllSerializableMembers]type!=null");
  107.            
  108.             if (type.IsInterface) {
  109.                 return new MemberInfo[0];
  110.             }
  111.            
  112.             if (!(CheckSerializable(type))) {
  113.                 throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_NonSerType"), type.FullName, type.Module.Assembly.FullName));
  114.             }
  115.            
  116.             //Get all of the serializable members in the class to be serialized.
  117.             typeMembers = GetSerializableMembers(type);
  118.            
  119.             //If this class doesn't extend directly from object, walk its hierarchy and
  120.             //get all of the private and assembly-access fields (e.g. all fields that aren't
  121.             //virtual) and include them in the list of things to be serialized.
  122.             parentType = (RuntimeType)(type.BaseType);
  123.             if (parentType != null && parentType != typeof(object)) {
  124.                 Type[] parentTypes = null;
  125.                 int parentTypeCount = 0;
  126.                 bool classNamesUnique = GetParentTypes(parentType, out parentTypes, out parentTypeCount);
  127.                 if (parentTypeCount > 0) {
  128.                     allMembers = new ArrayList();
  129.                     for (int i = 0; i < parentTypeCount; i++) {
  130.                         parentType = (RuntimeType)parentTypes[i];
  131.                         if (!CheckSerializable(parentType)) {
  132.                             throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_NonSerType"), parentType.FullName, parentType.Module.Assembly.FullName));
  133.                         }
  134.                        
  135.                         typeFields = parentType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
  136.                         string typeName = classNamesUnique ? parentType.Name : parentType.FullName;
  137.                         foreach (FieldInfo field in typeFields) {
  138.                             // Family and Assembly fields will be gathered by the type itself.
  139.                             if (!field.IsNotSerialized) {
  140.                                 allMembers.Add(new SerializationFieldInfo((RuntimeFieldInfo)field, typeName));
  141.                             }
  142.                         }
  143.                     }
  144.                     //If we actually found any new MemberInfo's, we need to create a new MemberInfo array and
  145.                     //copy all of the members which we've found so far into that.
  146.                     if (allMembers != null && allMembers.Count > 0) {
  147.                         MemberInfo[] membersTemp = new MemberInfo[allMembers.Count + typeMembers.Length];
  148.                         Array.Copy(typeMembers, membersTemp, typeMembers.Length);
  149.                         allMembers.CopyTo(membersTemp, typeMembers.Length);
  150.                         typeMembers = membersTemp;
  151.                     }
  152.                 }
  153.             }
  154.             return typeMembers;
  155.         }
  156.        
  157.         static bool GetParentTypes(Type parentType, out Type[] parentTypes, out int parentTypeCount)
  158.         {
  159.             //Check if there are any dup class names. Then we need to include as part of
  160.             //typeName to prefix the Field names in SerializationFieldInfo
  161.             /*out*/parentTypes = null;
  162.             /*out*/parentTypeCount = 0;
  163.             bool unique = true;
  164.             for (Type t1 = parentType; t1 != typeof(object); t1 = t1.BaseType) {
  165.                 if (t1.IsInterface)
  166.                     continue;
  167.                 string t1Name = t1.Name;
  168.                 for (int i = 0; unique && i < parentTypeCount; i++) {
  169.                     string t2Name = parentTypes[i].Name;
  170.                     if (t2Name.Length == t1Name.Length && t2Name[0] == t1Name[0] && t1Name == t2Name) {
  171.                         unique = false;
  172.                         break;
  173.                     }
  174.                 }
  175.                 //expand array if needed
  176.                 if (parentTypes == null || parentTypeCount == parentTypes.Length) {
  177.                     Type[] tempParentTypes = new Type[Math.Max(parentTypeCount * 2, 12)];
  178.                     if (parentTypes != null)
  179.                         Array.Copy(parentTypes, 0, tempParentTypes, 0, parentTypeCount);
  180.                     parentTypes = tempParentTypes;
  181.                 }
  182.                 parentTypes[parentTypeCount++] = t1;
  183.             }
  184.             return unique;
  185.         }
  186.        
  187.         // Get all of the Serializable members for a particular class. For all practical intents and
  188.         // purposes, this is the non-transient, non-static members (fields and properties). In order to
  189.         // be included, properties must have both a getter and a setter. N.B.: A class
  190.         // which implements ISerializable or has a serialization surrogate may not use all of these members
  191.         // (or may have additional members).
  192.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  193.         public static MemberInfo[] GetSerializableMembers(Type type)
  194.         {
  195.             return GetSerializableMembers(type, new StreamingContext(StreamingContextStates.All));
  196.         }
  197.        
  198.         // Get all of the Serializable Members for a particular class. If we're not cloning, this is all
  199.         // non-transient, non-static fields. If we are cloning, include the transient fields as well since
  200.         // we know that we're going to live inside of the same context.
  201.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  202.         public static MemberInfo[] GetSerializableMembers(Type type, StreamingContext context)
  203.         {
  204.             MemberInfo[] members;
  205.            
  206.             if (type == null) {
  207.                 throw new ArgumentNullException("type");
  208.             }
  209.            
  210.             if (!(type is RuntimeType)) {
  211.                 throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_InvalidType"), type.ToString()));
  212.             }
  213.            
  214.             MemberHolder mh = new MemberHolder(type, context);
  215.            
  216.             //If we've already gathered the members for this type, just return them.
  217.             if (m_MemberInfoTable.ContainsKey(mh)) {
  218.                 return m_MemberInfoTable[mh];
  219.             }
  220.            
  221.             lock (formatterServicesSyncObject) {
  222.                 //If we've already gathered the members for this type, just return them.
  223.                 if (m_MemberInfoTable.ContainsKey(mh)) {
  224.                     return m_MemberInfoTable[mh];
  225.                 }
  226.                
  227.                 members = InternalGetSerializableMembers((RuntimeType)type);
  228.                
  229.                 m_MemberInfoTable[mh] = members;
  230.             }
  231.            
  232.             return members;
  233.         }
  234.        
  235.         static readonly Type[] advancedTypes = new Type[] {typeof(System.Runtime.Remoting.ObjRef), typeof(System.DelegateSerializationHolder), typeof(System.Runtime.Remoting.IEnvoyInfo), typeof(System.Runtime.Remoting.Lifetime.ISponsor)};
  236.        
  237.         public static void CheckTypeSecurity(Type t, TypeFilterLevel securityLevel)
  238.         {
  239.             if (securityLevel == TypeFilterLevel.Low) {
  240.                 for (int i = 0; i < advancedTypes.Length; i++) {
  241.                     if (advancedTypes[i].IsAssignableFrom(t))
  242.                         throw new SecurityException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_TypeSecurity"), advancedTypes[i].FullName, t.FullName));
  243.                 }
  244.             }
  245.         }
  246.        
  247.         // Gets a new instance of the object. The entire object is initalized to 0 and no
  248.         // constructors have been run. **THIS MEANS THAT THE OBJECT MAY NOT BE IN A STATE
  249.         // CONSISTENT WITH ITS INTERNAL REQUIREMENTS** This method should only be used for
  250.         // deserialization when the user intends to immediately populate all fields. This method
  251.         // will not create an unitialized string because it is non-sensical to create an empty
  252.         // instance of an immutable type.
  253.         //
  254.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  255.         public static object GetUninitializedObject(Type type)
  256.         {
  257.             if (type == null) {
  258.                 throw new ArgumentNullException("type");
  259.             }
  260.            
  261.             if (!(type is RuntimeType)) {
  262.                 throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_InvalidType"), type.ToString()));
  263.             }
  264.            
  265.             return nativeGetUninitializedObject((RuntimeType)type);
  266.         }
  267.        
  268.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  269.         public static object GetSafeUninitializedObject(Type type)
  270.         {
  271.             if (type == null) {
  272.                 throw new ArgumentNullException("type");
  273.             }
  274.            
  275.             if (!(type is RuntimeType)) {
  276.                 throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_InvalidType"), type.ToString()));
  277.             }
  278.            
  279.             if (type == typeof(System.Runtime.Remoting.Messaging.ConstructionCall) || type == typeof(System.Runtime.Remoting.Messaging.LogicalCallContext) || type == typeof(System.Runtime.Remoting.Contexts.SynchronizationAttribute))
  280.                 return nativeGetUninitializedObject((RuntimeType)type);
  281.            
  282.             try {
  283.                 return nativeGetSafeUninitializedObject((RuntimeType)type);
  284.             }
  285.             catch (SecurityException e) {
  286.                 throw new SerializationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Serialization_Security"), type.FullName), e);
  287.             }
  288.         }
  289.        
  290.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  291.         private static extern object nativeGetSafeUninitializedObject(RuntimeType type);
  292.        
  293.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  294.         private static extern object nativeGetUninitializedObject(RuntimeType type);
  295.        
  296.         private static Binder s_binder = Type.DefaultBinder;
  297.         static internal void SerializationSetValue(MemberInfo fi, object target, object value)
  298.         {
  299.             BCLDebug.Assert(fi is RuntimeFieldInfo || fi is SerializationFieldInfo, "[SerializationSetValue]fi is RuntimeFieldInfo || fi is SerializationFieldInfo.");
  300.            
  301.             RtFieldInfo rfi = fi as RtFieldInfo;
  302.             if (rfi != null) {
  303.                 rfi.InternalSetValue(target, value, (BindingFlags)0, s_binder, null, false);
  304.             }
  305.             else {
  306.                 ((SerializationFieldInfo)fi).InternalSetValue(target, value, (BindingFlags)0, s_binder, null, false, true);
  307.             }
  308.         }
  309.        
  310.         // Fill in the members of obj with the data contained in data.
  311.         // Returns the number of members populated.
  312.         //
  313.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  314.         public static object PopulateObjectMembers(object obj, MemberInfo[] members, object[] data)
  315.         {
  316.             MemberInfo mi;
  317.            
  318.             BCLDebug.Trace("SER", "[PopulateObjectMembers]Enter.");
  319.            
  320.            
  321.             if (obj == null) {
  322.                 throw new ArgumentNullException("obj");
  323.             }
  324.            
  325.             if (members == null) {
  326.                 throw new ArgumentNullException("members");
  327.             }
  328.            
  329.             if (data == null) {
  330.                 throw new ArgumentNullException("data");
  331.             }
  332.            
  333.             if (members.Length != data.Length) {
  334.                 throw new ArgumentException(Environment.GetResourceString("Argument_DataLengthDifferent"));
  335.             }
  336.            
  337.             for (int i = 0; i < members.Length; i++) {
  338.                 mi = members[i];
  339.                
  340.                 if (mi == null) {
  341.                     throw new ArgumentNullException("members", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentNull_NullMember"), i));
  342.                 }
  343.                
  344.                
  345.                 //If we find an empty, it means that the value was never set during deserialization.
  346.                 //This is either a forward reference or a null. In either case, this may break some of the
  347.                 //invariants mantained by the setter, so we'll do nothing with it for right now.
  348.                 if (data[i] != null) {
  349.                     if (mi.MemberType == MemberTypes.Field) {
  350.                         SerializationSetValue(mi, obj, data[i]);
  351.                     }
  352.                     else {
  353.                         throw new SerializationException(Environment.GetResourceString("Serialization_UnknownMemberInfo"));
  354.                     }
  355.                    
  356.                     BCLDebug.Trace("SER", "[PopulateObjectMembers]\tType:", obj.GetType(), "\tMember:", members[i].Name, " with member type: ", ((FieldInfo)members[i]).FieldType);
  357.                 }
  358.                 //Console.WriteLine("X");
  359.             }
  360.            
  361.             BCLDebug.Trace("SER", "[PopulateObjectMembers]Leave.");
  362.            
  363.             return obj;
  364.         }
  365.        
  366.         // Extracts the data from obj. members is the array of members which we wish to
  367.         // extract (must be FieldInfos or PropertyInfos). For each supplied member, extract the matching value and
  368.         // return it in a Object[] of the same size.
  369.         //
  370.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  371.         public static object[] GetObjectData(object obj, MemberInfo[] members)
  372.         {
  373.            
  374.             if (obj == null) {
  375.                 throw new ArgumentNullException("obj");
  376.             }
  377.            
  378.             if (members == null) {
  379.                 throw new ArgumentNullException("members");
  380.             }
  381.            
  382.             int numberOfMembers = members.Length;
  383.            
  384.             object[] data = new object[numberOfMembers];
  385.             MemberInfo mi;
  386.            
  387.             for (int i = 0; i < numberOfMembers; i++) {
  388.                 mi = members[i];
  389.                
  390.                 if (mi == null) {
  391.                     throw new ArgumentNullException("members", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentNull_NullMember"), i));
  392.                 }
  393.                
  394.                 if (mi.MemberType == MemberTypes.Field) {
  395.                     BCLDebug.Assert(mi is RuntimeFieldInfo || mi is SerializationFieldInfo, "[FormatterServices.GetObjectData]mi is RuntimeFieldInfo || mi is SerializationFieldInfo.");
  396.                    
  397.                     RtFieldInfo rfi = mi as RtFieldInfo;
  398.                     if (rfi != null) {
  399.                         data[i] = rfi.InternalGetValue(obj, false);
  400.                     }
  401.                     else {
  402.                         data[i] = ((SerializationFieldInfo)mi).InternalGetValue(obj, false);
  403.                     }
  404.                 }
  405.                 else {
  406.                     throw new SerializationException(Environment.GetResourceString("Serialization_UnknownMemberInfo"));
  407.                 }
  408.             }
  409.            
  410.             return data;
  411.         }
  412.        
  413.        
  414. /*=============================GetTypeFromAssembly==============================
  415.         **Action:
  416.         **Returns:
  417.         **Arguments:
  418.         **Exceptions:
  419.         ==============================================================================*/       
  420.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  421.         public static Type GetTypeFromAssembly(Assembly assem, string name)
  422.         {
  423.             if (assem == null)
  424.                 throw new ArgumentNullException("assem");
  425.             return assem.GetType(name, false, false);
  426.         }
  427.        
  428. /*============================LoadAssemblyFromString============================
  429.         **Action: Loads an assembly from a given string.  The current assembly loading story
  430.         **        is quite confusing.  If the assembly is in the fusion cache, we can load it
  431.         **        using the stringized-name which we transmitted over the wire.  If that fails,
  432.         **        we try for a lookup of the assembly using the simple name which is the first
  433.         **        part of the assembly name.  If we can't find it that way, we'll return null
  434.         **        as our failure result.
  435.         **Returns: The loaded assembly or null if it can't be found.
  436.         **Arguments: assemblyName -- The stringized assembly name.
  437.         **Exceptions: None
  438.         ==============================================================================*/       
  439.         static internal Assembly LoadAssemblyFromString(string assemblyName)
  440.         {
  441.             //
  442.             // Try using the stringized assembly name to load from the fusion cache.
  443.             //
  444.             BCLDebug.Trace("SER", "[LoadAssemblyFromString]Looking for assembly: ", assemblyName);
  445.             Assembly found = Assembly.Load(assemblyName);
  446.             return found;
  447.         }
  448.         static internal Assembly LoadAssemblyFromStringNoThrow(string assemblyName)
  449.         {
  450.             try {
  451.                 return LoadAssemblyFromString(assemblyName);
  452.             }
  453.             catch (Exception e) {
  454.                 BCLDebug.Trace("SER", "[LoadAssemblyFromString]", e.ToString());
  455.             }
  456.             return null;
  457.         }
  458.     }
  459. }

Developer Fusion