예제 #1
0
        protected override object Extract(Box box, Type type, Mapper mapper)
        {
            var obj = Activator.CreateInstance(type);

            for (int i = 0; i < box.Values.Kvps.Keys.Count; i++)
            {
                var          key   = box.Values.Kvps.Keys[i];
                var          value = box.Values.Kvps.Values[i];
                string       name  = mapper.GetString(key);
                MemberInfo[] mis   = type.GetMember(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                if (mis.Length != 1)
                {
                    throw new Exception("ambiguous struct member name " + name);
                }
                MemberInfo mi = mis[0];
                if (StorableAttribute.IsStorable(mi))
                {
                    throw new PersistenceException("Don't use storable attributes for structs as all fields are serialized automatically.");
                }
                if (mi.MemberType == MemberTypes.Field)
                {
                    ((FieldInfo)mi).SetValue(obj, mapper.GetObject(value));
                }
                else
                {
                    throw new Exception("invalid struct member type " + mi.MemberType.ToString());
                }
            }

            return(obj);
        }
예제 #2
0
 public ComponentInfo(string name, string fullName, T memberInfo, Type declaringType, StorableAttribute storableAttribute, bool readable, bool writeable)
 {
     Name              = name;
     FullName          = fullName;
     MemberInfo        = memberInfo;
     DeclaringType     = declaringType;
     StorableAttribute = storableAttribute;
     Readable          = readable;
     Writeable         = writeable;
 }
예제 #3
0
        private void Reflect()
        {
            var type = Type;

            if (StorableTypeAttribute != null)
            {
                StorableTypeAttributeGuid = StorableTypeAttribute.Guid.ToString().ToUpperInvariant();
                string guidPrefix = StorableTypeAttributeGuid;
                // check constructors
                if (!type.IsValueType && !type.IsEnum && !type.IsInterface &&
                    GetStorableConstructor() == null && GetDefaultConstructor() == null)
                {
                    throw new PersistenceException("No storable constructor or parameterless constructor found.", type);
                }

                var fields     = new List <ComponentInfo <FieldInfo> >();
                var properties = new List <ComponentInfo <PropertyInfo> >();
                var beforeSerializationHooks  = new List <MethodInfo>();
                var afterDeserializationHooks = new List <MethodInfo>();

                if (StorableTypeAttribute.MemberSelection != StorableMemberSelection.AllProperties)
                {
                    // TODO: improved performance for static fields
                    var fieldInfos = type.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic)
                                     .Where(x => !x.Name.StartsWith("<") && !x.Name.EndsWith("k__BackingField")); // exclude backing fields

                    if (StorableTypeAttribute.MemberSelection == StorableMemberSelection.MarkedOnly)
                    {
                        fieldInfos = fieldInfos.Where(StorableAttribute.IsStorable).ToArray();
                    }

                    foreach (var field in fieldInfos)
                    {
                        var name   = field.Name;
                        var attrib = StorableAttribute.GetStorableAttribute(field);

                        if (attrib != null)
                        {
                            if (!string.IsNullOrEmpty(attrib.Name) && !string.IsNullOrEmpty(attrib.OldName))
                            {
                                throw new PersistenceException($"Field {field.Name} cannot use Name and OldName at the same time.", type);
                            }

                            if (!string.IsNullOrEmpty(attrib.Name))
                            {
                                name = attrib.Name;
                            }
                            else if (!string.IsNullOrEmpty(attrib.OldName))
                            {
                                name = attrib.OldName;
                            }
                        }

                        var nameParts  = name.Split('.').ToArray();
                        var sourceType = type;
                        var tmpGuid    = Guid.Empty;

                        for (int i = 0; i < nameParts.Length; i++)
                        {
                            var part = nameParts[i];
                            if (part == "base")
                            {
                                sourceType = sourceType.BaseType;
                            }
                            else if (Guid.TryParse(part, out tmpGuid))
                            {
                                if (i != 0 || nameParts.Length != 2)
                                {
                                    throw new PersistenceException($"Field {field.Name} has an invalid path.", type);
                                }
                                guidPrefix = tmpGuid.ToString().ToUpper();
                                break;
                            }
                            else if (i != nameParts.Length - 1)
                            {
                                throw new PersistenceException($"Field {field.Name} has an invalid path.", type);
                            }
                            else
                            {
                                break;
                            }
                        }

                        if (sourceType != type)
                        {
                            name       = nameParts[nameParts.Length - 1];
                            guidPrefix = StorableTypeAttribute.GetStorableTypeAttribute(sourceType).Guid.ToString().ToUpperInvariant();
                        }
                        else if (tmpGuid != Guid.Empty)
                        {
                            name = nameParts[nameParts.Length - 1];
                        }

                        fields.Add(new ComponentInfo <FieldInfo>(name, guidPrefix + "." + name, field, type, attrib, true, true));
                    }
                }

                if (StorableTypeAttribute.MemberSelection != StorableMemberSelection.AllFields)
                {
                    // TODO: improved performance for static properties
                    var propertyInfos = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic)
                                        .Where(x => !x.GetIndexParameters().Any()); // exclude indexed properties

                    if (StorableTypeAttribute.MemberSelection == StorableMemberSelection.MarkedOnly)
                    {
                        propertyInfos = propertyInfos.Where(StorableAttribute.IsStorable).ToArray();
                    }

                    foreach (var property in propertyInfos)
                    {
                        var name   = property.Name;
                        var attrib = StorableAttribute.GetStorableAttribute(property);

                        if (attrib != null)
                        {
                            if (!string.IsNullOrEmpty(attrib.Name) && !string.IsNullOrEmpty(attrib.OldName))
                            {
                                throw new PersistenceException($"Property {property.Name} cannot use Name and OldName at the same time.", type);
                            }

                            if (attrib.AllowOneWay && !string.IsNullOrEmpty(attrib.OldName))
                            {
                                throw new PersistenceException($"Property {property.Name} cannot use AllowOneWay and OldName at the same time.", type);
                            }

                            if (!string.IsNullOrEmpty(attrib.Name))
                            {
                                name = attrib.Name;
                            }
                            else if (!string.IsNullOrEmpty(attrib.OldName))
                            {
                                name = attrib.OldName;
                            }
                        }

                        if ((!property.CanRead || !property.CanWrite) && (attrib == null || !attrib.AllowOneWay && string.IsNullOrEmpty(attrib.OldName)))
                        {
                            throw new PersistenceException($"Property {property.Name} must be readable and writable or have one way serialization explicitly enabled or use OldName.", type);
                        }

                        var nameParts  = name.Split('.').ToArray();
                        var sourceType = type;
                        var tmpGuid    = Guid.Empty;

                        for (int i = 0; i < nameParts.Length; i++)
                        {
                            var part = nameParts[i];
                            if (part == "base")
                            {
                                sourceType = sourceType.BaseType;
                            }
                            else if (Guid.TryParse(part, out tmpGuid))
                            {
                                if (i != 0 || nameParts.Length != 2)
                                {
                                    throw new PersistenceException($"Property {property.Name} has an invalid path.", type);
                                }
                                guidPrefix = tmpGuid.ToString().ToUpper();
                                break;
                            }
                            else if (i != nameParts.Length - 1)
                            {
                                throw new PersistenceException($"Property {property.Name} has an invalid path.", type);
                            }
                            else
                            {
                                break;
                            }
                        }

                        if (sourceType != type)
                        {
                            name       = nameParts[nameParts.Length - 1];
                            guidPrefix = StorableTypeAttribute.GetStorableTypeAttribute(sourceType).Guid.ToString().ToUpper();
                        }
                        else if (tmpGuid != Guid.Empty)
                        {
                            name = nameParts[nameParts.Length - 1];
                        }

                        var declaringType = GetPropertyDeclaringBaseType(property);
                        properties.Add(new ComponentInfo <PropertyInfo>(name, guidPrefix + "." + name, property, declaringType, attrib, property.CanRead, property.CanWrite));
                    }
                }

                var methodInfos = type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic)
                                  .Where(StorableHookAttribute.IsStorableHook)
                                  .Where(x => x.ReturnType == typeof(void) && !x.GetParameters().Any());

                foreach (var method in methodInfos)
                {
                    foreach (var attrib in StorableHookAttribute.GetStorableHookAttributes(method))
                    {
                        if (attrib.HookType == HookType.BeforeSerialization)
                        {
                            beforeSerializationHooks.Add(method);
                        }
                        if (attrib.HookType == HookType.AfterDeserialization)
                        {
                            afterDeserializationHooks.Add(method);
                        }
                    }
                }

                Fields = fields;
                WriteableProperties       = properties.Where(p => p.Writeable).ToArray();
                ReadableProperties        = properties.Where(p => p.Readable).ToArray();
                BeforeSerializationHooks  = beforeSerializationHooks;
                AfterDeserializationHooks = afterDeserializationHooks;
            }
        }