public IDictionary <String, Object> Serialize(Object obj, JavaScriptSerializer serializer, HashSet <String> index, RestSerializationDepth depth, RestSerializationDepth toDepth, bool inList)
        {
            Type runtimeType = obj.GetType();

            // Create a dictionary and add the rest uri as a default property
            IDictionary <String, Object> result = new Dictionary <String, Object>();

            // If we have been asked to serialise nothing, return the empty result
            if (toDepth == RestSerializationDepth.None)
            {
                return(result);
            }

            if (obj is Proxy)
            {
                String context    = String.Join(".", runtimeType.Namespace.Split('.').Skip(1));
                object rawId      = runtimeType.GetProperty("Id", BindingFlags.Public | BindingFlags.Instance).GetValue(obj);
                String identifier = rawId == null || (rawId.GetType().In(typeof(int), typeof(long), typeof(byte), typeof(short)) && rawId.ConvertTo <long>() == 0) ? "" : rawId.ConvertTo <String>();
                String uri        = String.Concat(context, "/", runtimeType.Name, "/", identifier);
                if (index.Contains(uri))
                {
                    return(null);
                }

                result.Add("uri", uri);
                index.Add(uri);
            }

            // Add each public instance property to the dictionary
            PropertyInfo[] properties = runtimeType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            List <string>  toIgnore   = Ignore.ContainsKey(obj.GetType()) ? Ignore[obj.GetType()] : new List <string>();
            List <string>  toInclude  = Include.ContainsKey(obj.GetType()) ? Include[obj.GetType()] : new List <string>();
            Dictionary <string, RestSerializationDepth> listDepths = NamedListsResolveToDepth.ContainsKey(obj.GetType()) ? NamedListsResolveToDepth[obj.GetType()] : new Dictionary <string, RestSerializationDepth>();

            foreach (PropertyInfo property in properties.Where(prop => prop.CanRead && !toIgnore.Contains(prop.Name) && (toInclude.Count == 0 || prop.Name == "Id" || toInclude.Contains(prop.Name))))
            {
                // Exclude members that are marked as non-serialized
                if (!property.GetCustomAttributes().OfType <NonSerializedAttribute>().Any())
                {
                    if ((property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Collection <>)) || property.PropertyType.IsArray)
                    {
                        // Collections are (by default) serialized for root objects only
                        if ((!inList && depth <= _listsAtDepth && depth <= toDepth && !listDepths.ContainsKey(property.Name)) || (listDepths.ContainsKey(property.Name) && listDepths[property.Name] != RestSerializationDepth.None))
                        {
                            RestSerializationDepth listDepth = listDepths.ContainsKey(property.Name) ? listDepths[property.Name] : _listToDepth;
                            result[property.Name] = (property.GetValue(obj) as IEnumerable).OfType <Object>().Select(element => this.Serialize(element, serializer, index, RestSerializationDepth.Root, listDepth, true));
                        }
                    }
                    else if (typeof(Consensus.Common.ICodeModel).IsAssignableFrom(property.PropertyType))
                    {
                        // Code Models are serialized on root and child objects.
                        if (!inList && depth < toDepth && depth != RestSerializationDepth.None)
                        {
                            result[property.Name] = this.Serialize(property.GetValue(obj), serializer, index, RestSerializationDepth.None, toDepth, inList);
                        }
                    }
                    else if (this.SupportedTypes.Contains(property.PropertyType))
                    {
                        // Other models are serialized on root and child objects.
                        if (depth < toDepth && depth != RestSerializationDepth.None)
                        {
                            if (depth == RestSerializationDepth.Root)
                            {
                                result[property.Name] = this.Serialize(property.GetValue(obj), serializer, index, RestSerializationDepth.Child, toDepth, inList);
                            }
                            else if (depth == RestSerializationDepth.Child)
                            {
                                result[property.Name] = this.Serialize(property.GetValue(obj), serializer, index, RestSerializationDepth.GrandChild, toDepth, inList);
                            }
                        }
                    }
                    else if (property.PropertyType.IsEnum)
                    {
                        // Native property types are serialized on all objects
                        result[property.Name] = property.GetValue(obj).ToString();
                    }
                    else if (property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?))
                    {
                        DateTime?value = property.GetValue(obj).ConvertTo <DateTime?>();
                        if (value.HasValue)
                        {
                            result[property.Name] = value.Value.ToString("dd MMMM yyyy HH:mm:ss");
                        }
                        else
                        {
                            result[property.Name] = null;
                        }
                    }
                    else
                    {
                        result[property.Name] = property.GetValue(obj);
                    }
                }
            }
            return(result);
        }