Ejemplo n.º 1
0
        /// <summary>
        /// Create an instance of an object and immediately set fields on it from the document.
        /// The type of instance is supplied via the generic parameter.
        /// </summary>
        public static T CreateInstance <T>(DocNode dict, ConfigOptions?options = null) where T : new()
        {
            var obj = (object)System.Activator.CreateInstance <T>();

            SetFieldsOnObject(ref obj, dict, DefaultedOptions(options));
            return((T)obj);
        }
Ejemplo n.º 2
0
        public static object FromVector3(object obj, DocNode value)
        {
            DocNodeType parsedType = value.Type;

            if (parsedType == DocNodeType.Scalar)     // Vector3, 3 => new Vector3(3,3, 3);
            {
                float single = value.AsFloat();
                return(new Vector3(single, single, single));
            }
            else                          // Vector3, [1,2,3] => new Vector2(1,2,3);
            {
                float v1 = value[0].AsFloat();
                float v2 = v1;
                float v3 = v1;
                if (value.Count > 1)
                {
                    v2 = value[1].AsFloat();
                    v3 = 0;
                }
                if (value.Count > 2)
                {
                    v3 = value[2].AsFloat();
                }
                return(new Vector3(v1, v2, v3));
            }
        }
Ejemplo n.º 3
0
        public static T As <T>(this DocNode doc)
        {
            T retval = default(T);

            ConfigReifier.Reify <T>(ref retval, doc);
            return(retval);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Create an instance of an object and immediately set fields on it from the document.
        /// The type of instance is supplied explicitly as the first argument.
        /// Requires a zero-args constructor on the type though it doesn't enforce that.
        /// </summary>
        public static object CreateInstance(Type t, DocNode dict, ConfigOptions?options = null)
        {
            var obj = System.Activator.CreateInstance(t);

            SetFieldsOnObject(ref obj, dict, DefaultedOptions(options));
            return(obj);
        }
Ejemplo n.º 5
0
        static object FromVector2(object obj, DocNode value)
        {
            // TODO (Graham): Make a non-boxing version of this?
            // TODO (Graham): The scalar and n-dimensional support here is non-obvious. Those cases seem like they'd be nearly always mistakes. Better to throw an exception here.

            var parsedType = value.Type;

            // Parse a scalar float and use that for both components of the vector.
            // 3 => new Vector2(3,3)
            if (parsedType == DocNodeType.Scalar)
            {
                var single = value.As <float>();
                return(new Vector2(single, single));
            }

            // Parse a list of floats and use those as the vector components.
            // Supports the following conversions:
            // [1] => Vector2(1,1)
            // [1,2] => new Vector2(1,2);
            // [1,2,3,4,5,6] => new Vector2(1,2);
            float x = value[0].As <float>();
            float y = x;

            if (value.Count > 1)
            {
                y = value[1].As <float>();
            }

            return(new Vector2(x, y));
        }
Ejemplo n.º 6
0
        static object FromVector3(object obj, DocNode value)
        {
            // TODO (Graham): Make a non-boxing version of this?
            // TODO (Graham): The scalar and n-dimensional support here is non-obvious. Those cases seem like they'd be nearly always mistakes. Better to throw an exception here.

            var parsedType = value.Type;

            if (parsedType == DocNodeType.Scalar)   // Vector3, 3 => new Vector3(3,3, 3);
            {
                float single = value.As <float>();
                return(new Vector3(single, single, single));
            }

            // Vector3, [1,2,3] => new Vector2(1,2,3);
            float x = value[0].As <float>();
            float y = x;
            float z = x;

            if (value.Count > 1)
            {
                y = value[1].As <float>();
                z = 0;
            }

            if (value.Count > 2)
            {
                z = value[2].As <float>();
            }

            return(new Vector3(x, y, z));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Sets all members on the struct *obj* (which must not be null) from *dict*.
        /// </summary>
        public static void SetFieldsOnStruct <T>(ref T obj, DocNode dict, ConfigOptions?options = null) where T : struct
        {
            Type type    = typeof(T);
            var  setCopy = (object)obj;

            SetFieldsOnObject(type, ref setCopy, dict, DefaultedOptions(options));
            obj = (T)setCopy;
        }
Ejemplo n.º 8
0
        static void SetField(FieldInfo f, ref object obj, DocNode value, ConfigOptions?options)
        {
            if (obj == null && !f.IsStatic)
            {
                return;                            // silently don't set non-static fields
            }
            Type fieldType = f.FieldType;
            var  existing  = f.GetValue(obj);
            var  updated   = ValueOfType(fieldType, existing, value, options);
            var  setCopy   = obj; // needed for structs

            f.SetValue(setCopy, updated);
            obj = setCopy;
        }
Ejemplo n.º 9
0
 public static bool Contains(this DocNode doc, string item)
 {
     if (doc.Type != DocNodeType.List)
     {
         throw new DocNodeAccessException("Expected List, is " + doc.Type);
     }
     for (int i = 0; i < doc.Count; i++)
     {
         if (doc[i].StringValue == item)
         {
             return(true);
         }
     }
     return(false);
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Sets all members on the object *obj* (which must not be null) from *dict*.
        /// Expects *obj* to be a plain class, but if it's a boxed struct it will work as well.
        /// </summary>
        public static void SetFieldsOnObject <T>(ref T obj, DocNode dict, ConfigOptions?options = null) where T : class
        {
            Config.Assert(obj != null, "Can't SetFields on null");
            Type type = typeof(T);

            if (type == typeof(object))
            {
                // caller is using an object, but that is not the real type
                type = obj.GetType();
            }
            var setCopy = (object)obj;

            SetFieldsOnObject(type, ref setCopy, dict, DefaultedOptions(options));
            obj = (T)setCopy;
        }
Ejemplo n.º 11
0
        public override bool TryGetValue(string key, bool ignoreCase, out DocNode result)
        {
            CheckTypeIs(DocNodeType.Dictionary);
            foreach (var kvp in dictionary)
            {
                if (string.Equals(kvp.Key, key, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
                {
                    result = kvp.Value;
                    return(true);
                }
            }

            result = null;
            return(false);
        }
Ejemplo n.º 12
0
        static object FromColor(object obj, DocNode value)
        {
            if (value.Type == DocNodeType.Scalar)
            {
                return((Color)ParseColor32(value.StringValue));
            }

            var colorValues = new List <float>();

            foreach (var docValue in value.Values)
            {
                colorValues.Add(docValue.As <float>());
            }

            // see if any of the values are over 1; if so, treat each as if they're in the range 0-255 instead of 0-1
            bool isBytes = false;

            foreach (float colorVal in colorValues)
            {
                isBytes |= colorVal > 1;
            }

            // If color values are in the 0-255 range, normalize them to 0-1
            if (isBytes)
            {
                for (int i = 0; i < colorValues.Count; i++)
                {
                    colorValues[i] = colorValues[i] / 255;
                }
            }

            // Color, [1,1,1] => new Color(1,1,1,1)
            if (colorValues.Count == 3)
            {
                return(new Color(colorValues[0], colorValues[1], colorValues[2]));
            }

            // Color, [1,1,1,1] => new Color(1,1,1,1)
            if (colorValues.Count == 4)
            {
                return(new Color(colorValues[0], colorValues[1], colorValues[2], colorValues[3]));
            }

            // TODO (Graham): Throw an exception here?  We couldn't parse the value into a color so better to complain loudly than fail silently.

            return(Color.magenta);
        }
Ejemplo n.º 13
0
        public static object FromVector2(object obj, DocNode value)
        {
            DocNodeType parsedType = value.Type;

            if (parsedType == DocNodeType.Scalar)     // Vector2, 3 => new Vector2(3,3);
            {
                var single = value.AsFloat();
                return(new Vector2(single, single));
            }
            else                          // Vector2, [1,2] => new Vector2(1,2);
            {
                float v1 = value[0].AsFloat();
                float v2 = v1;
                if (value.Count > 1)
                {
                    v2 = value[1].AsFloat();
                }
                return(new Vector2(v1, v2));
            }
        }
Ejemplo n.º 14
0
        public static object FromColor(object obj, DocNode value)
        {
            if (value.Type == DocNodeType.Scalar)
            {
                return((Color)ParseColor32(value.StringValue));
            }

            var c = value.Values.Select(x => x.AsFloat()).ToList();

            // see if any of the values are over 1; if so, treat each as if they're in the range 0-255
            bool isBytes = false;

            for (int i = 0; i < c.Count; i++)
            {
                if (c[i] > 1)
                {
                    isBytes = true;
                }
            }
            for (int i = 0; i < c.Count; i++)
            {
                if (isBytes)
                {
                    c[i] = c[i] / 255;
                }
            }

            // Color, [1,1,1] => new Color(1,1,1,1)
            if (c.Count == 3)
            {
                return(new Color(c[0], c[1], c[2]));
            }
            // Color, [1,1,1,1] => new Color(1,1,1,1)
            if (c.Count == 4)
            {
                return(new Color(c[0], c[1], c[2], c[3]));
            }
            return(Color.magenta);
        }
Ejemplo n.º 15
0
 public static bool AsBool(this DocNode doc)
 {
     return(As <bool>(doc));
 }
Ejemplo n.º 16
0
 public static int AsInt(this DocNode doc)
 {
     return(As <int>(doc));
 }
Ejemplo n.º 17
0
 /// <summary>
 /// Sets up *obj* based on the contents of the parsed document *doc*
 /// So if obj is a Thing:
 ///   public class Thing {
 ///      float m1;
 ///      string m2;
 ///   }
 ///
 /// You can create a new instance, or set an existing instance's fields with this parsed document:
 ///  {"m1":1.0, "m2":"test"}
 ///
 /// *obj* can be null; if it is it gets assigned a new instance based on its type and the contents of *doc* (this is why the parameter is a ref)
 ///
 /// Works on static and private variables, too.
 /// </summary>
 public static void Reify <T>(ref T obj, DocNode doc, ConfigOptions?options = null)
 {
     obj = (T)ValueOfType(typeof(T), obj, doc, options);
 }
Ejemplo n.º 18
0
        public static void SetParentDefaults <K, V>(
            ref Dictionary <K, V> container,
            DocNode doc,
            Func <V, K> getBasedOn,
            string[] unparentableFieldNames = null)
        {
            // clear existing values before the reify; because later we bake them
            var fields = typeof(V).GetFields();

            if (container != null)
            {
                foreach (var kv in container)
                {
                    foreach (var field in fields)
                    {
                        field.SetValue(kv.Value, GetDefault(field.FieldType));
                    }
                }
            }

            Config.Reify(ref container, doc);

            var parentRelationships = new Dictionary <V, V>();

            // hook up parent references
            foreach (var kv in container)
            {
                var val     = kv.Value;
                var basedOn = getBasedOn(val);
                if (basedOn == null)
                {
                    continue;
                }
                if (!container.ContainsKey(basedOn))
                {
                    Config.Log(LogVerbosity.Error,
                               string.Format("In file {0}, {1} is based on {2}, which doesn't exist",
                                             doc.SourceInformation, val, basedOn));
                    continue;
                }

                parentRelationships[val] = container[basedOn];
            }

            // set fields from the parents
            foreach (var kv in container)
            {
                var val = kv.Value;
                foreach (var field in fields)
                {
                    if (field.IsSpecialName)
                    {
                        continue;
                    }
                    if (unparentableFieldNames != null)
                    {
                        bool shouldNotParentThisField = false;
                        for (int i = 0; i < unparentableFieldNames.Length; i++)
                        {
                            if (field.Name == unparentableFieldNames[i])
                            {
                                shouldNotParentThisField = true;
                                break;
                            }
                        }
                        if (shouldNotParentThisField)
                        {
                            continue;
                        }
                    }

                    var fieldValue = GetParentedFieldValue(field, val, parentRelationships, 0);
                    field.SetValue(val, fieldValue);
                }
            }
        }
Ejemplo n.º 19
0
 public void Add(string key, DocNode value)
 {
     AssertTypeIs(DocNodeType.Dictionary);
     m_dictionary.Add(key, value);
 }
Ejemplo n.º 20
0
        //////////////////////////////////////////////////////////////////////
        // Composition methods

        public void Add(DocNode d)
        {
            AssertTypeIs(DocNodeType.List);
            m_list.Add(d);
        }
Ejemplo n.º 21
0
 public static string AsString(this DocNode doc)
 {
     return(doc.StringValue);
 }
Ejemplo n.º 22
0
        /// Sets all members on the object *obj* based on the appropriate key from *doc*
        static void SetFieldsOnObject(Type type, ref object obj, DocNode doc, ConfigOptions options)
        {
            if (doc == null)
            {
                return;
            }

            bool caseInsensitive = (options & ConfigOptions.CaseSensitive) != ConfigOptions.CaseSensitive;
            bool checkMissing    = (options & ConfigOptions.AllowMissingFields) != ConfigOptions.AllowMissingFields;
            bool checkExtra      = (options & ConfigOptions.AllowExtraFields) != ConfigOptions.AllowExtraFields;
            var  classAttrs      = ReflectionCache.GetCustomAttributes(type);

            for (int i = 0; i < classAttrs.Length; i++)
            {
                if (classAttrs[i] is ConfigMandatoryAttribute)
                {
                    checkMissing = true; continue;
                }
                if (classAttrs[i] is ConfigAllowMissingAttribute)
                {
                    checkMissing = false; continue;
                }
            }
            if (GetFirstNonObjectBaseClass(type).ToString() == "UnityEngine.Object")
            {
                // Unity Objects have a lot of fields, it never makes sense to set most of them from configs
                checkMissing = false;
            }

            var setCopy = obj;

            if (doc.Type != DocNodeType.Dictionary)
            {
                // special-case behavior, set the first instance field on it from the doc
                var allFields = ReflectionCache.GetInstanceFields(type);
                Config.Assert(allFields.Length == 1, "Trying to set a field of type: ",
                              type, allFields.Length, "from value of wrong type:",
                              doc.Type == DocNodeType.Scalar ? doc.StringValue : doc.Type.ToString(),
                              "at",
                              doc.SourceInformation);
                SetField(allFields[0], ref setCopy, doc, options);
                obj = setCopy;
                return;
            }

            var typeFields        = new HashSet <string>();
            var usedFields        = new HashSet <string>();
            var lowercasedDocKeys = new Dictionary <string, string>();

            if (caseInsensitive)
            {
                foreach (var kv in doc.Pairs)
                {
                    lowercasedDocKeys[kv.Key.ToLower()] = kv.Key;
                }
            }

            bool anyFieldMandatory = false;

            foreach (ReflectionCache.CachedFieldInfo cf in ReflectionCache.GetStrippedFields(type, caseInsensitive))
            {
                var f = cf.field;
                // get attributes for the field
                bool isMandatory  = false;
                bool allowMissing = false;
                bool ignore       = false;
                var  attrs        = ReflectionCache.GetCustomAttributes(f);
                for (int i = 0; i < attrs.Length; i++)
                {
                    if (attrs[i] is ConfigMandatoryAttribute)
                    {
                        isMandatory = true; anyFieldMandatory = true; continue;
                    }
                    if (attrs[i] is ConfigAllowMissingAttribute)
                    {
                        allowMissing = true; continue;
                    }
                    if (attrs[i] is ConfigIgnoreAttribute)
                    {
                        ignore = true; continue;
                    }
                }
                if (IsDelegate(f.FieldType))
                {
                    ignore = true;                         // never report postdocs as present or missing
                }
                // figure out the canonical name for the field
                string strippedName = cf.strippedName;

                // do meta stuff based on attributes/validation
                if (ignore)
                {
                    usedFields.Add(strippedName); // pretend like we set it
                    continue;
                }
                if (checkMissing || isMandatory)
                {
                    typeFields.Add(strippedName);
                }

                string docKey = null;
                if (caseInsensitive)
                {
                    lowercasedDocKeys.TryGetValue(strippedName, out docKey);
                }
                if (docKey == null)
                {
                    docKey = strippedName;
                }
                if (doc.ContainsKey(docKey))
                {
                    usedFields.Add(strippedName);
                    SetField(f, ref setCopy, doc[docKey], options);
                }
                else if (allowMissing)
                {
                    usedFields.Add(strippedName);  // pretend like we set it
                }
            }

            // validation ---------
            if (checkExtra)
            {
                // check whether any fields in the doc were unused
                var extra = new List <string>();
                foreach (var kv in doc.Pairs)
                {
                    var key = kv.Key;
                    if (caseInsensitive)
                    {
                        key = ReflectionCache.GetLowercase(key);
                    }
                    if (!usedFields.Contains(key))
                    {
                        extra.Add(key);
                    }
                }
                if (extra.Count > 0)
                {
                    throw new ParseException("Extra doc fields: " + JoinList(extra, ", ") + " " + doc.SourceInformation, null);
                }
            }

            if (checkMissing || anyFieldMandatory)
            {
                // check whether any fields in the class were unset
                var missing = new List <string>();
                foreach (var typeField in typeFields)
                {
                    if (!usedFields.Contains(typeField))
                    {
                        missing.Add(typeField);
                    }
                }
                if (missing.Count > 0)
                {
                    throw new ParseException("Missing doc fields: " + JoinList(missing, ", ") + " " + doc.SourceInformation, null);
                }
            }
            obj = setCopy;
        }
Ejemplo n.º 23
0
 /// <summary>
 /// Sets up static variables (and only static variables) on type *T* based on the contents of the parsed document *doc*
 ///
 /// Ignores any fields in *doc* that are for non-static fields.
 /// </summary>
 public static void ReifyStatic <T>(DocNode doc, ConfigOptions?options = null)
 {
     ReifyStatic(typeof(T), doc, options);
 }
Ejemplo n.º 24
0
 public void Add(DocNode d)
 {
     CheckTypeIs(DocNodeType.List);
     list.Add(d);
 }
Ejemplo n.º 25
0
        /// <summary>
        /// Same as ReifyStatic<T>, but with a type argument instead of a generic.  Static classes can't be used in generics, so use this version instead.
        /// </summary>
        public static void ReifyStatic(Type type, DocNode doc, ConfigOptions?options = null)
        {
            object dummyObj = null;

            SetFieldsOnObject(type, ref dummyObj, doc, DefaultedOptions(options));
        }
Ejemplo n.º 26
0
 public void Add(string key, DocNode value)
 {
     CheckTypeIs(DocNodeType.Dictionary);
     dictionary.Add(key, value);
 }
Ejemplo n.º 27
0
        static object ValueOfType(Type fieldType, object existing, DocNode value, ConfigOptions?options)
        {
            try {
                if (fieldType == typeof(System.Boolean))
                {
                    return(Convert.ToBoolean(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                // floating-point value types
                if (fieldType == typeof(System.Single))
                {
                    return(Convert.ToSingle(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Double))
                {
                    return(Convert.ToDouble(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Decimal))
                {
                    return(Convert.ToDecimal(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                // integral value types
                if (fieldType == typeof(System.SByte))
                {
                    return(Convert.ToSByte(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Byte))
                {
                    return(Convert.ToByte(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Char))
                {
                    return(Convert.ToChar(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Int16))
                {
                    return(Convert.ToInt16(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.UInt16))
                {
                    return(Convert.ToUInt16(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Int32))
                {
                    return(Convert.ToInt32(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.UInt32))
                {
                    return(Convert.ToUInt32(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Int64))
                {
                    return(Convert.ToInt64(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.UInt64))
                {
                    return(Convert.ToUInt64(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(string))
                {
                    return(value.StringValue);
                }
                if (fieldType.IsEnum)          // AudioRolloffMode, "Custom" => AudioRolloffMode.Custom
                {
                    return(Enum.Parse(fieldType, value.StringValue, true));
                }
                if (fieldType == typeof(DocNode))
                {
                    return(value);
                }
                if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    if (value.Type == DocNodeType.Scalar && value.StringValue == "null")
                    {
                        return(null);
                    }
                    var innerType = Nullable.GetUnderlyingType(fieldType);
                    return(ValueOfType(innerType, existing, value, options));
                }
                if (s_fromDocs.ContainsKey(fieldType))
                {
                    existing = s_fromDocs[fieldType](existing, value);
                    return(CallPostDoc(fieldType, existing));
                }
                if (fieldType.IsArray)                      // [1,2,3,4,5] => new int[] { 1,2,3,4,5 }
                {
                    Type arrTyp = fieldType.GetElementType();
                    if (fieldType.GetArrayRank() == 2)
                    {
                        var firstList = value[0];
                        var destArr   = Array.CreateInstance(arrTyp, firstList.Count, value.Count);
                        int j         = 0;
                        foreach (DocNode subList in value.Values)
                        {
                            int i = 0;
                            foreach (var val in subList.Values.Select(item => ValueOfType(arrTyp, null, item, options)))
                            {
                                destArr.SetValue(val, new int[] { i, j });
                                i++;
                            }
                            j++;
                        }
                        return(destArr);
                    }
                    else
                    {
                        var iexisting = (Array)existing;
                        if (iexisting == null)
                        {
                            iexisting = Array.CreateInstance(arrTyp, value.Count);
                        }
                        else if (iexisting.Length != value.Count)
                        {
                            var oldArr = iexisting;
                            iexisting = Array.CreateInstance(arrTyp, value.Count);
                            for (int i = 0; i < iexisting.Length && i < oldArr.Length; i++)
                            {
                                iexisting.SetValue(oldArr.GetValue(i), i);
                            }
                        }
                        for (int i = 0; i < iexisting.Length; i++)
                        {
                            var existingElt = iexisting.GetValue(i);
                            var updatedElt  = ValueOfType(arrTyp, existingElt, value[i], options);
                            iexisting.SetValue(updatedElt, i);
                        }
                        return(iexisting);
                    }
                }
                if (fieldType.IsGenericType)
                {
                    // this chunk of code handles generic dictionaries and lists; it only
                    // works with string keys on the dictionaries, and for now any values
                    // must have zero-args constructors
                    if (fieldType.GetGenericTypeDefinition() == typeof(Dictionary <,>))
                    {
                        Type[] typeParameters = fieldType.GetGenericArguments();

                        if (existing == null)
                        {
                            existing = Activator.CreateInstance(fieldType);
                        }
                        var              iexisting = (System.Collections.IDictionary)existing;
                        Type             kType     = typeParameters[0];
                        Type             vType     = typeParameters[1];
                        ComposedDocNode  keyNode   = new ComposedDocNode(DocNodeType.Scalar); // can reuse this one object
                        HashSet <object> usedKeys  = new HashSet <object>();

                        // create/update all pairs in the doc
                        foreach (var kv in value.Pairs)
                        {
                            keyNode.StringValue = kv.Key;
                            object existingKey   = ValueOfType(kType, null, keyNode, options);
                            object existingValue = null;
                            if (iexisting.Contains(existingKey))
                            {
                                existingValue = iexisting[existingKey];
                            }
                            var updated = ValueOfType(vType, existingValue, kv.Value, options);
                            iexisting[existingKey] = updated;
                            usedKeys.Add(existingKey);
                        }
                        // remove any pairs not in the doc
                        var keysToRemove = new List <object>();
                        foreach (var k in iexisting.Keys)
                        {
                            if (!usedKeys.Contains(k))
                            {
                                keysToRemove.Add(k);
                            }
                        }
                        foreach (var k in keysToRemove)
                        {
                            iexisting.Remove(k);
                        }
                        return(iexisting);
                    }
                    if (fieldType.GetGenericTypeDefinition() == typeof(List <>))
                    {
                        Type[] typeParameters = fieldType.GetGenericArguments();
                        if (existing == null)
                        {
                            existing = Activator.CreateInstance(fieldType);
                        }

                        var iexisting = (System.Collections.IList)existing;
                        while (iexisting.Count > value.Count)
                        {
                            iexisting.RemoveAt(iexisting.Count - 1);
                        }
                        for (int i = 0; i < iexisting.Count; i++)
                        {
                            var existingElt = iexisting[i];
                            var updatedElt  = ValueOfType(typeParameters[0], existingElt, value[i], options);
                            iexisting[i] = updatedElt;
                        }
                        while (iexisting.Count < value.Count)
                        {
                            var newElt = ValueOfType(typeParameters[0], null, value[iexisting.Count], options);
                            iexisting.Add(newElt);
                        }
                        return(existing);
                    }
                }
                var fromDocMethod = ReflectionCache.GetFromDoc(fieldType);
                if (fromDocMethod != null)   // if there's a custom parser method on the class, delegate all work to that
                // TODO: this doesn't do inherited FromDoc methods properly, but it should
                {
                    try {
                        existing = fromDocMethod.Invoke(null, new[] { existing, value });
                        return(CallPostDoc(fieldType, existing));
                    } catch (System.Reflection.TargetInvocationException e) {
                        throw e.InnerException;
                    }
                }
                if (fieldType.IsClass)
                {
                    if (existing == null)
                    {
                        existing = CreateInstance(fieldType, value, options);
                        return(CallPostDoc(fieldType, existing));
                    }
                    else
                    {
                        SetFieldsOnObject(fieldType, ref existing, value, DefaultedOptions(options));
                        return(CallPostDoc(fieldType, existing));
                    }
                }
                if (fieldType.IsValueType)
                {
                    // a struct; set the members and return it
                    if (existing == null)
                    {
                        // structs can be null when boxed
                        existing = CreateInstance(fieldType, value, options);
                        return(CallPostDoc(fieldType, existing));
                    }
                    else
                    {
                        SetFieldsOnObject(fieldType, ref existing, value, DefaultedOptions(options));
                        return(CallPostDoc(fieldType, existing));
                    }
                }
            } catch (Exception e) {
                throw new ParseException("Exception based on document starting at: " + value.SourceInformation, e);
            }

            throw new System.NotSupportedException("Don't know how to update value of type " + fieldType.ToString());
        }
Ejemplo n.º 28
0
 public static float AsFloat(this DocNode doc)
 {
     return(As <float>(doc));
 }