示例#1
0
        /// <summary>Restores a collection from the config node.</summary>
        /// <remarks>This method never throws.</remarks>
        /// <param name="node">The node to read the state from.</param>
        /// <param name="instance">
        /// The owner of the field. It can be <c>null</c> for the static fields.
        /// </param>
        void ReadCollectionFromConfig(ConfigNode node, object instance)
        {
            var value = fieldInfo.GetValue(instance);

            if (value == null)
            {
                // Collections are the complex objects, they must exist in order to be restored.
                DebugEx.Warning("Skip reading collection field {0}.{1} due to it's not initalized",
                                fieldInfo.DeclaringType.FullName, fieldInfo.Name);
                return;
            }
            collectionProto.ClearItems(value);
            if (isCompound)
            {
                // For compound items read nodes and have them parsed.
                var itemCfgs = ConfigAccessor.GetNodesByPath(node, cfgPath);
                if (itemCfgs != null)
                {
                    foreach (var itemCfg in itemCfgs)
                    {
                        var itemValue = Activator.CreateInstance(collectionProto.GetItemType());
                        DeserializeCompoundFieldsFromNode(itemCfg, itemValue);
                        collectionProto.AddItem(value, itemValue);
                    }
                }
            }
            else
            {
                // For ordinary items read strings and have them parsed.
                var itemCfgs = ConfigAccessor.GetValuesByPath(node, cfgPath);
                if (itemCfgs != null)
                {
                    foreach (var itemCfg in itemCfgs)
                    {
                        try {
                            object itemValue;
                            if (isCustomSimpleType)
                            {
                                itemValue = Activator.CreateInstance(collectionProto.GetItemType());
                                ((IPersistentField)itemValue).ParseFromString(itemCfg);
                            }
                            else
                            {
                                itemValue = simpleTypeProto.ParseFromString(itemCfg, collectionProto.GetItemType());
                            }
                            collectionProto.AddItem(value, itemValue);
                        } catch (Exception ex) {
                            DebugEx.Error("Cannot parse value \"{0}\" as {1}: {2}",
                                          itemCfgs, collectionProto.GetItemType().FullName, ex.Message);
                        }
                    }
                }
            }
        }
示例#2
0
        /// <param name="fieldInfo">An annotated field metadata.</param>
        /// <param name="fieldAttr">An annotation of the field.</param>
        public PersistentField(FieldInfo fieldInfo, PersistentFieldAttribute fieldAttr)
        {
            this.fieldInfo = fieldInfo;
            cfgPath        = fieldAttr.path;
            var ordinaryType = fieldInfo.FieldType;

            if (fieldAttr.collectionTypeProto != null)
            {
                collectionProto =
                    Activator.CreateInstance(fieldAttr.collectionTypeProto, new[] { fieldInfo.FieldType })
                    as AbstractCollectionTypeProto;
                ordinaryType = collectionProto.GetItemType();
            }
            simpleTypeProto =
                Activator.CreateInstance(fieldAttr.ordinaryTypeProto)
                as AbstractOrdinaryValueTypeProto;
            isCustomSimpleType = typeof(IPersistentField).IsAssignableFrom(ordinaryType);

            // Determine if field's or collection item's type is a class (compound type).
            isCompound = !simpleTypeProto.CanHandle(ordinaryType) && !isCustomSimpleType &&
                         (ordinaryType.IsValueType && !ordinaryType.IsEnum || // IsStruct
                          ordinaryType.IsClass && ordinaryType != typeof(string) &&
                          !ordinaryType.IsEnum); // IsClass

            if (!isCompound && !simpleTypeProto.CanHandle(ordinaryType) && !isCustomSimpleType)
            {
                Debug.LogErrorFormat(
                    "Proto {0} cannot handle value in field {1}.{2}",
                    ordinaryType.FullName, fieldInfo.DeclaringType.FullName, fieldInfo.Name);
                isDisabled = true;
            }

            // For a compound type retrieve all its persisted fields.
            if (isCompound && !isDisabled)
            {
                // Ignore static fields of the compound type since it can be used by multiple persistent
                // fields or as an item in a collection field.
                // Also, ignore groups in the compound types to reduce configuration complexity.
                compoundTypeFields =
                    PersistentFieldsFactory.GetPersistentFields(
                        ordinaryType, false /* needStatic */, true /* needInstance */, null /* group */)
                    // Parent nodes have to be handled before children!
                    .OrderBy(x => string.Join("/", x.cfgPath))
                    .ToArray();

                // Disable if cannot deal with the field anyways.
                if (compoundTypeFields.Length == 0 && !typeof(IConfigNode).IsAssignableFrom(ordinaryType))
                {
                    Debug.LogErrorFormat(
                        "Compound type in field {0}.{1} has no persistent fields and doesn't implement"
                        + " IConfigNode",
                        fieldInfo.DeclaringType.FullName, fieldInfo.Name);
                    isDisabled = true;
                }
            }
        }
示例#3
0
 /// <summary>Returns type of an item in the colelction.</summary>
 /// <returns>Item's type.</returns>
 internal Type GetItemType()
 {
     return(collectionProto.GetItemType());
 }
示例#4
0
        /// <summary>Reads field from a config node.</summary>
        /// <param name="node">A node to read state from.</param>
        /// <param name="instance">An owner of the field. Can be <c>null</c> for static fields.</param>
        public void ReadFromConfig(ConfigNode node, object instance)
        {
            var value = fieldInfo.GetValue(instance);

            if (collectionProto != null)
            {
                // For collection field use existing object and restore its items.
                if (value == null)
                {
                    Debug.LogWarningFormat("Skip reading collection field {0}.{1} due to it's not initalized",
                                           fieldInfo.DeclaringType.FullName, fieldInfo.Name);
                    return;
                }
                collectionProto.ClearItems(value);
                if (isCompound)
                {
                    // For compound items read nodes and have them parsed.
                    var itemCfgs = ConfigAccessor.GetNodesByPath(node, cfgPath);
                    if (itemCfgs != null)
                    {
                        foreach (var itemCfg in itemCfgs)
                        {
                            var itemValue = Activator.CreateInstance(collectionProto.GetItemType());
                            DeserializeCompoundFieldsFromNode(itemCfg, itemValue);
                            collectionProto.AddItem(value, itemValue);
                        }
                    }
                }
                else
                {
                    // For ordinary items read strings and have them parsed.
                    var itemCfgs = ConfigAccessor.GetValuesByPath(node, cfgPath);
                    if (itemCfgs != null)
                    {
                        foreach (var itemCfg in itemCfgs)
                        {
                            try {
                                object itemValue;
                                if (isCustomSimpleType)
                                {
                                    itemValue = Activator.CreateInstance(collectionProto.GetItemType());
                                    ((IPersistentField)itemValue).ParseFromString(itemCfg);
                                }
                                else
                                {
                                    itemValue = simpleTypeProto.ParseFromString(itemCfg, collectionProto.GetItemType());
                                }
                                collectionProto.AddItem(value, itemValue);
                            } catch (Exception ex) {
                                Debug.LogErrorFormat("Cannot parse value \"{0}\" as {1}: {2}",
                                                     itemCfgs, collectionProto.GetItemType().FullName, ex.Message);
                            }
                        }
                    }
                }
            }
            else
            {
                // For ordinary field just restore value and assign it to the field.
                if (isCompound)
                {
                    if (value != null)
                    {
                        DeserializeCompoundFieldsFromNode(ConfigAccessor.GetNodeByPath(node, cfgPath), value);
                    }
                    else
                    {
                        Debug.LogWarningFormat("Skip reading compound field {0}.{1} due to it's not initalized",
                                               fieldInfo.DeclaringType.FullName, fieldInfo.Name);
                    }
                }
                else
                {
                    var cfgValue = ConfigAccessor.GetValueByPath(node, cfgPath);
                    if (cfgValue != null)
                    {
                        try {
                            object fieldValue;
                            if (isCustomSimpleType)
                            {
                                // Prefer the existing instance of the field value when available.
                                fieldValue = value ?? Activator.CreateInstance(fieldInfo.FieldType);
                                ((IPersistentField)fieldValue).ParseFromString(cfgValue);
                            }
                            else
                            {
                                fieldValue = simpleTypeProto.ParseFromString(cfgValue, fieldInfo.FieldType);
                            }
                            fieldInfo.SetValue(instance, fieldValue);
                        } catch (Exception ex) {
                            Debug.LogErrorFormat("Cannot parse value \"{0}\" as {1}: {2}",
                                                 cfgValue, fieldInfo.FieldType.FullName, ex.Message);
                        }
                    }
                }
            }
        }