File: AuthoringOM\Serializer\FormatterServicesNoSerializableCheck.cs
Project: ndp\cdf\src\WF\Common\System.Workflow.ComponentModel.csproj (System.Workflow.ComponentModel)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*============================================================
**
** Class: SerializationFieldInfo
**
**
** Purpose: Provides a methods of representing imaginary fields
** which are unique to serialization.  In this case, what we're
** representing is the private members of parent classes.  We
** aggregate the FieldInfo associated with this member 
** and return a managled form of the name.  The name that we
** return is .parentname.fieldname
**
**
============================================================*/
using System;
using System.Reflection;
using System.Threading;
using System.Globalization;
using System.Security.Permissions;
using System.Collections;
using System.Collections.Generic;
using System.Workflow.ComponentModel;
 
 
namespace System.Runtime.Serialization
{
    internal static class FormatterServicesNoSerializableCheck
    {
        private struct MemberInfoName
        {
            public MemberInfo[] MemberInfo;
            public string[] Names;
        }
        private static Dictionary<Type, MemberInfoName> m_MemberInfoTable = new Dictionary<Type, MemberInfoName>(32);
        internal static readonly String FakeNameSeparatorString = "+";
 
        private static Object s_FormatterServicesSyncObject = null;
 
        private static Object formatterServicesSyncObject
        {
            get
            {
                if (s_FormatterServicesSyncObject == null)
                {
                    Object o = new Object();
                    Interlocked.CompareExchange(ref s_FormatterServicesSyncObject, o, null);
                }
                return s_FormatterServicesSyncObject;
            }
        }
 
        private static MemberInfo[] GetSerializableMembers2(Type type)
        {
            // get the list of all fields
            FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            int countProper = 0;
            for (int i = 0; i < fields.Length; i++)
            {
                if ((fields[i].Attributes & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized)
                    continue;
                countProper++;
            }
            if (countProper != fields.Length)
            {
                FieldInfo[] properFields = new FieldInfo[countProper];
                countProper = 0;
                for (int i = 0; i < fields.Length; i++)
                {
                    if ((fields[i].Attributes & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized)
                        continue;
                    properFields[countProper] = fields[i];
                    countProper++;
                }
                return properFields;
            }
            else
                return fields;
        }
        private static bool CheckSerializable(Type type)
        {
            return true;
            /*
            if (type.IsSerializable)
            {
                return true;
            }
            return false;
            */
        }
        private static MemberInfo[] InternalGetSerializableMembers(Type type, out string[] typeNames)
        {
            typeNames = null;
 
            ArrayList allMembers = null;
            ArrayList allNames = null;
            MemberInfo[] typeMembers;
            FieldInfo[] typeFields;
            Type parentType;
 
            //<
 
            if (type.IsInterface)
            {
                return new MemberInfo[0];
            }
 
            //Get all of the serializable members in the class to be serialized.
            typeMembers = GetSerializableMembers2(type);
            if (typeMembers != null)
            {
                typeNames = new string[typeMembers.Length];
                for (int index = 0; index < typeMembers.Length; index++)
                    typeNames[index] = typeMembers[index].Name;
            }
 
            //If this class doesn't extend directly from object, walk its hierarchy and 
            //get all of the private and assembly-access fields (e.g. all fields that aren't
            //virtual) and include them in the list of things to be serialized.  
            parentType = (Type)(type.BaseType);
            if (parentType != null && parentType != typeof(Object))
            {
                Type[] parentTypes = null;
                int parentTypeCount = 0;
                bool classNamesUnique = GetParentTypes(parentType, out parentTypes, out parentTypeCount);
                if (parentTypeCount > 0)
                {
                    allMembers = new ArrayList();
                    allNames = new ArrayList();
                    for (int i = 0; i < parentTypeCount; i++)
                    {
                        parentType = (Type)parentTypes[i];
                        if (!CheckSerializable(parentType))
                        {
                            throw new SerializationException(); //String.Format(Environment.GetResourceString("Serialization_NonSerType"), parentType.FullName, parentType.Module.Assembly.FullName));
                        }
 
                        typeFields = parentType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
                        String typeName = classNamesUnique ? parentType.Name : parentType.FullName;
                        foreach (FieldInfo field in typeFields)
                        {
                            // Family and Assembly fields will be gathered by the type itself.
                            if (field.IsPrivate && !field.IsNotSerialized)
                            {
                                allMembers.Add(field);
                                allNames.Add(String.Concat(typeName, FakeNameSeparatorString, field.Name));
                                //allMembers.Add(new SerializationFieldInfo(field, typeName));
                            }
                        }
                    }
                    //If we actually found any new MemberInfo's, we need to create a new MemberInfo array and
                    //copy all of the members which we've found so far into that.
                    if (allMembers != null && allMembers.Count > 0)
                    {
                        MemberInfo[] membersTemp = new MemberInfo[allMembers.Count + typeMembers.Length];
                        Array.Copy(typeMembers, membersTemp, typeMembers.Length);
                        allMembers.CopyTo(membersTemp, typeMembers.Length);
                        typeMembers = membersTemp;
 
                        string[] namesTemp = new string[allNames.Count + typeNames.Length];
                        Array.Copy(typeNames, namesTemp, typeNames.Length);
                        allNames.CopyTo(namesTemp, typeNames.Length);
                        typeNames = namesTemp;
                    }
                }
            }
            return typeMembers;
        }
 
        private static bool GetParentTypes(Type parentType, out Type[] parentTypes, out int parentTypeCount)
        {
            //Check if there are any dup class names. Then we need to include as part of
            //typeName to prefix the Field names in SerializationFieldInfo
            /*out*/
            parentTypes = null;
            /*out*/
            parentTypeCount = 0;
            bool unique = true;
            for (Type t1 = parentType; t1 != typeof(object); t1 = t1.BaseType)
            {
                if (t1.IsInterface) continue;
                string t1Name = t1.Name;
                for (int i = 0; unique && i < parentTypeCount; i++)
                {
                    string t2Name = parentTypes[i].Name;
                    if (t2Name.Length == t1Name.Length && t2Name[0] == t1Name[0] && t1Name == t2Name)
                    {
                        unique = false;
                        break;
                    }
                }
                //expand array if needed
                if (parentTypes == null || parentTypeCount == parentTypes.Length)
                {
                    Type[] tempParentTypes = new Type[Math.Max(parentTypeCount * 2, 12)];
                    if (parentTypes != null)
                        Array.Copy(parentTypes, 0, tempParentTypes, 0, parentTypeCount);
                    parentTypes = tempParentTypes;
                }
                parentTypes[parentTypeCount++] = t1;
            }
            return unique;
        }
 
        // Get all of the Serializable members for a particular class.  For all practical intents and
        // purposes, this is the non-transient, non-static members (fields and properties).  In order to
        // be included, properties must have both a getter and a setter.  N.B.: A class
        // which implements ISerializable or has a serialization surrogate may not use all of these members
        // (or may have additional members).
        public static MemberInfo[] GetSerializableMembers(Type type, out string[] names)
        {
            names = null;
 
            MemberInfoName members;
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
 
            lock (formatterServicesSyncObject)
            {
                //If we've already gathered the members for this type, just return them
                if (m_MemberInfoTable.TryGetValue(type, out members))
                {
                    names = members.Names;
                    return members.MemberInfo;
                }
            }
            members.MemberInfo = InternalGetSerializableMembers(type, out members.Names);
            lock (formatterServicesSyncObject)
            {
                //If we've already gathered the members for this type, just return them.
                MemberInfoName insertedMembers;
                if (m_MemberInfoTable.TryGetValue(type, out insertedMembers))
                {
                    names = insertedMembers.Names;
                    return insertedMembers.MemberInfo;
                }
                m_MemberInfoTable[type] = members;
            }
            names = members.Names;
            return members.MemberInfo;
        }
    }
}