Example #1
0
 public TypeInfo(Type type)
 {
     Type = type;
     StorableTypeAttribute     = StorableTypeAttribute.GetStorableTypeAttribute(type);
     StorableTypeAttributeGuid = string.Empty;
     Fields = Enumerable.Empty <ComponentInfo <FieldInfo> >();
     WriteableProperties       = Enumerable.Empty <ComponentInfo <PropertyInfo> >();
     ReadableProperties        = Enumerable.Empty <ComponentInfo <PropertyInfo> >();
     BeforeSerializationHooks  = Enumerable.Empty <MethodInfo>();
     AfterDeserializationHooks = Enumerable.Empty <MethodInfo>();
     Used = 0;
     Reflect();
 }
Example #2
0
        public void UpdateRegisteredTypes()
        {
            foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (asm.IsDynamic)
                {
                    continue;
                }
                if (cachedAssemblies.Contains(asm.FullName))
                {
                    continue;
                }
                cachedAssemblies.Add(asm.FullName);

                foreach (var t in asm.GetTypes())
                {
                    if (typeof(ITransformer).IsAssignableFrom(t) && !t.IsAbstract)
                    {
                        var transformer = (ITransformer)Activator.CreateInstance(t);
                        RegisterTransformer(transformer);
                    }
                }

                foreach (var t in asm.GetTypes())
                {
                    if (StorableTypeAttribute.IsStorableType(t))
                    {
                        type2Guid.Add(t, StorableTypeAttribute.GetStorableTypeAttribute(t).Guid);
                        foreach (var guid in StorableTypeAttribute.GetStorableTypeAttribute(t).Guids)
                        {
                            if (guid2Type.ContainsKey(guid))
                            {
                                throw new PersistenceException($"The GUID {guid} is already used by type {guid2Type[guid]}.", t);
                            }
                            guid2Type.Add(guid, t);
                        }
                    }
                    else if (typeof(IStorableTypeMap).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)
                    {
                        var knownTypeMap = (IStorableTypeMap)Activator.CreateInstance(t);
                        foreach (var tup in knownTypeMap.KnownStorableTypes)
                        {
                            RegisterType(tup.Item1, tup.Item2);
                        }
                    }
                }
            }
        }
Example #3
0
        public static StorableTypeAttribute GetStorableTypeAttribute(Type type)
        {
            StorableTypeAttribute attrib = null;

            if (!nonStorableTypes.Contains(type) && !attributeCache.TryGetValue(type, out attrib))
            {
                attrib = (StorableTypeAttribute)GetCustomAttribute(type, typeof(StorableTypeAttribute), false);
                if (attrib != null)
                {
                    attributeCache[type] = attrib;
                }
                else
                {
                    nonStorableTypes.Add(type);
                }
            }

            return(attrib);
        }
        protected override void Populate(Box box, object value, Mapper mapper)
        {
            var kvpBox = new RepeatedValueBox();

            kvpBox.Kvps = new RepeatedKeyValuePairsBox();
            box.Values  = kvpBox;

            var keys   = kvpBox.Kvps.Keys;
            var values = kvpBox.Kvps.Values;

            foreach (DictionaryEntry item in (IDictionary)value)
            {
                if (mapper.CancellationToken.IsCancellationRequested)
                {
                    return;
                }
                keys.Add(mapper.GetBoxId(item.Key));
                values.Add(mapper.GetBoxId(item.Value));
            }

            var type         = value.GetType();
            var propertyInfo = type.GetProperty("Comparer");
            var comparer     = propertyInfo.GetValue(value);

            var comparerType = comparer.GetType();

            if (StorableTypeAttribute.IsStorableType(comparerType))
            {
                kvpBox.ComparerId = mapper.GetBoxId(comparer);
            }
            else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any())
            {
                throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields");
            }
            else
            {
                kvpBox.ComparerTypeId = mapper.GetTypeMetadataId(comparerType, transformer: null); // there is no transformer for the comparer type
            }
        }
Example #5
0
        private static void ExecuteAfterDeserializationHooks(IEnumerator <object> e)
        {
            var emptyArgs = new object[0];

            while (e.MoveNext())
            {
                var obj = e.Current;

                if (obj == null || !StorableTypeAttribute.IsStorableType(obj.GetType()))
                {
                    continue;
                }

                var typeList = new LinkedList <Type>();
                for (var type = obj.GetType(); type != null; type = type.BaseType)
                {
                    typeList.AddFirst(type);
                }

                foreach (var type in typeList)
                {
                    if (!StorableTypeAttribute.IsStorableType(type))
                    {
                        continue;
                    }

                    var typeInfo = StaticCache.GetTypeInfo(type);
                    foreach (var hook in typeInfo.AfterDeserializationHooks)
                    {
                        try {
                            hook.Invoke(obj, emptyArgs);
                        } catch (TargetInvocationException t) {
                            throw t.InnerException;
                        }
                    }
                }
            }
        }
Example #6
0
        protected override void Populate(Box box, object value, Mapper mapper)
        {
            box.Values = new RepeatedValueBox();
            var type         = value.GetType();
            var propertyInfo = type.GetProperty("Comparer");
            var comparer     = propertyInfo.GetValue(value);

            var comparerType = comparer.GetType();

            if (StorableTypeAttribute.IsStorableType(comparerType))
            {
                box.Values.ComparerId = mapper.GetBoxId(comparer);
            }
            else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any())
            {
                throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields");
            }
            else
            {
                box.Values.ComparerTypeId = mapper.GetTypeMetadataId(comparerType, transformer: null); // there is no transformer for the comparer type
            }
            AddRange((IEnumerable)value, box.Values, mapper);
        }
Example #7
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;
            }
        }
        protected override void Populate(Box box, object value, Mapper mapper)
        {
            if (mapper.CancellationToken.IsCancellationRequested)
            {
                return;
            }
            var emptyArgs = new object[0];
            var type      = value.GetType();

            // traverse type hierarchy

            var typeInfo = Mapper.StaticCache.GetTypeInfo(type);

            do
            {
                foreach (var hook in typeInfo.BeforeSerializationHooks)
                {
                    try {
                        hook.Invoke(value, emptyArgs);
                    } catch (TargetInvocationException t) {
                        throw t.InnerException;
                    }
                }

                type     = type.BaseType;
                typeInfo = Mapper.StaticCache.GetTypeInfo(type);
            } while (StorableTypeAttribute.IsStorableType(type) && !mapper.CancellationToken.IsCancellationRequested);


            var set = new HashSet <Tuple <Type, string> >();

            // traverse type hierarchy
            var membersBox = new StorableTypeMembersBox();

            box.Members = membersBox;

            type     = value.GetType();
            typeInfo = Mapper.StaticCache.GetTypeInfo(type);

            membersBox.StorableTypeMetadataId = mapper.GetStorableTypeMetadata(typeInfo.StorableTypeAttributeGuid);
            var layout = mapper.GetStorableTypeLayout(membersBox.StorableTypeMetadataId);

            while (StorableTypeAttribute.IsStorableType(type) && !mapper.CancellationToken.IsCancellationRequested)
            {
                foreach (var componentInfo in typeInfo.Fields)
                {
                    if (!layout.IsPopulated)
                    {
                        layout.MemberNames.Add(componentInfo.Name);
                    }
                    membersBox.ValueBoxId.Add(mapper.GetBoxId(componentInfo.MemberInfo.GetValue(value)));
                }

                foreach (var componentInfo in typeInfo.ReadableProperties)
                {
                    var declaringType = componentInfo.DeclaringType;

                    if (!set.Add(Tuple.Create(declaringType, componentInfo.Name)))
                    {
                        continue;
                    }

                    if (!layout.IsPopulated)
                    {
                        layout.MemberNames.Add(componentInfo.Name);
                    }
                    membersBox.ValueBoxId.Add(mapper.GetBoxId(componentInfo.MemberInfo.GetValue(value, null)));
                }

                layout.IsPopulated = true;

                // prepare for next iteration
                type = type.BaseType;
                if (StorableTypeAttribute.IsStorableType(type))
                {
                    typeInfo = Mapper.StaticCache.GetTypeInfo(type);
                    layout.ParentLayoutId = mapper.GetStorableTypeMetadata(typeInfo.StorableTypeAttributeGuid);
                    layout = mapper.GetStorableTypeLayout(layout.ParentLayoutId);
                }
            }
        }
 public override bool CanTransformType(Type type)
 {
     return(StorableTypeAttribute.IsStorableType(type) && !type.IsValueType && !type.IsEnum || // don't transform structs or enums
            type.BaseType != null && CanTransformType(type.BaseType));
 }
        public override void FillFromBox(object obj, Box box, Mapper mapper)
        {
            if (mapper.CancellationToken.IsCancellationRequested)
            {
                return;
            }

            var dict    = new Dictionary <string, object>();
            var members = box.Members;
            var layout  = mapper.GetStorableTypeLayout(members.StorableTypeMetadataId);

            var valueIdx = 0;

            while (layout != null && !mapper.CancellationToken.IsCancellationRequested)
            {
                for (int j = 0; j < layout.MemberNames.Count; j++)
                {
                    string key   = mapper.GetComponentInfoKey(layout.TypeGuid, layout.MemberNames[j]);
                    object value = mapper.GetObject(members.ValueBoxId[valueIdx++]);
                    dict.Add(key, value);
                }
                layout = mapper.GetStorableTypeLayout(layout.ParentLayoutId);
            }

            var type      = mapper.StorableTypeMetadataToType(mapper.GetTypeMetadata(box.TypeMetadataId));
            var typeInfo  = Mapper.StaticCache.GetTypeInfo(type);
            var typeStack = new Stack <Tuple <Type, TypeInfo> >();

            do
            {
                typeInfo = Mapper.StaticCache.GetTypeInfo(type);
                typeStack.Push(Tuple.Create(type, typeInfo));
                type = type.BaseType;
            } while (StorableTypeAttribute.IsStorableType(type) && !mapper.CancellationToken.IsCancellationRequested);

            foreach (var frame in typeStack)
            {
                type     = frame.Item1;
                typeInfo = frame.Item2;

                // set stored or default values for all fields and properties
                foreach (var componentInfo in typeInfo.Fields)
                {
                    var attrib    = componentInfo.StorableAttribute;
                    var fieldInfo = componentInfo.MemberInfo;

                    if (dict.TryGetValue(componentInfo.FullName, out object value))
                    {
                        fieldInfo.SetValue(obj, value);
                    }
                    else if (attrib != null && attrib.DefaultValue != null)
                    {
                        fieldInfo.SetValue(obj, attrib.DefaultValue);
                    }
                }

                foreach (var componentInfo in typeInfo.WriteableProperties)
                {
                    var attrib       = componentInfo.StorableAttribute;
                    var propertyInfo = componentInfo.MemberInfo;

                    if (dict.TryGetValue(componentInfo.FullName, out object value))
                    {
                        propertyInfo.SetValue(obj, value, null);
                    }
                    else if (attrib != null && attrib.DefaultValue != null)
                    {
                        propertyInfo.SetValue(obj, attrib.DefaultValue, null);
                    }
                }
            }
        }