Beispiel #1
0
        private SerializerPair CreateGenericSerializer(MemberInfo member, TypeInfo typeInfo, Type implementingType, TypeInfo implementingTypeInfo)
        {
            var genericDefinition = implementingType.GetGenericTypeDefinition();

            if (genericDefinition == typeof(RdProperty <>))
            {
                return(CreateStaticReaderSingleGeneric(member, typeInfo.AsType(), implementingType, allowNullable: true));
            }

            if (genericDefinition == typeof(RdSignal <>) ||
                genericDefinition == typeof(RdList <>) ||
                genericDefinition == typeof(RdSet <>))
            {
                return(CreateStaticReaderSingleGeneric(member, typeInfo.AsType(), implementingType, allowNullable: false));
            }

            if (genericDefinition == typeof(RdMap <,>)
                // || genericDefinition == typeof(RdCall<,>) not supported yet
                )
            {
                return(CreateStaticReaderTwoGeneric(member, typeInfo.AsType(), implementingType));
            }

            if (genericDefinition == typeof(Nullable <>))
            {
                var genericTypeArgument = implementingTypeInfo.GetGenericArguments()[0];
                var nullableSerializer  = (SerializerPair)ReflectionUtil.InvokeGenericThis(this, nameof(RegisterNullable), genericTypeArgument);
                return(nullableSerializer);
            }

            throw new Exception($"Unable to register generic type: {typeInfo}");
        }
        internal static Type ToType(TypeInfo typeInfo)
        {
#if (NET35 || NET40)
            return(typeInfo);
#else
            return(typeInfo?.AsType());
#endif
        }
Beispiel #3
0
        internal static Type ToType(TypeInfo typeInfo)
        {
#if (!NETSTANDARD1_3)
            return(typeInfo);
#else
            return(typeInfo?.AsType());
#endif
        }
Beispiel #4
0
        private SerializerPair GetMemberSerializer(MemberInfo member, TypeInfo typeInfo)
        {
            var implementingType     = ReflectionSerializerVerifier.GetImplementingType(typeInfo);
            var implementingTypeInfo = implementingType.GetTypeInfo();

            if (mySerializers.TryGetValue(typeInfo.AsType(), out var pair))
            {
                return(pair);
            }

            if (ReflectionSerializerVerifier.IsValueTuple(implementingTypeInfo))
            {
                return((SerializerPair)ReflectionUtil.InvokeGenericThis(this, nameof(CreateValueTupleSerializer), typeInfo.AsType()));
            }

            var hasRdAttribute = ReflectionSerializerVerifier.HasRdModelAttribute(typeInfo) || ReflectionSerializerVerifier.HasRdExtAttribute(typeInfo);

            if (typeInfo.IsGenericType && !hasRdAttribute)
            {
                return(CreateGenericSerializer(member, typeInfo, implementingType, implementingTypeInfo));
            }

            if (typeInfo.IsEnum)
            {
                var serializer = ReflectionUtil.InvokeGenericThis(this, nameof(CreateEnumSerializer), typeInfo.AsType());
                return((SerializerPair)serializer);
            }

            if (typeInfo.IsArray)
            {
                var serializer = ReflectionUtil.InvokeGenericThis(this, nameof(CreateArraySerializer), typeInfo.GetElementType());
                return((SerializerPair)serializer);
            }

            if (hasRdAttribute)
            {
                return(GetOrRegisterSerializerInternal(typeInfo.AsType()));
            }

            Assertion.Fail($"Unable to serialize member: {member.DeclaringType?.ToString(true)}.{member.Name} of type {typeInfo.ToString(true)}");

            return(null);
        }
        public static Type GetImplementingType(TypeInfo typeInfo)
        {
            if (!typeInfo.IsGenericType)
            {
                return(typeInfo.AsType());
            }

            var genericDefinition = typeInfo.GetGenericTypeDefinition();

            if (genericDefinition == typeof(IViewableProperty <>))
            {
                return(typeof(RdProperty <>).MakeGenericType(typeInfo.GetGenericArguments()));
            }

            if (genericDefinition == typeof(ISignal <>))
            {
                return(typeof(RdSignal <>).MakeGenericType(typeInfo.GetGenericArguments()));
            }
            if (genericDefinition == typeof(IViewableSet <>))
            {
                return(typeof(RdSet <>).MakeGenericType(typeInfo.GetGenericArguments()));
            }
            if (genericDefinition == typeof(IViewableList <>))
            {
                return(typeof(RdList <>).MakeGenericType(typeInfo.GetGenericArguments()));
            }

            if (genericDefinition == typeof(IViewableMap <,>))
            {
                return(typeof(RdMap <,>).MakeGenericType(typeInfo.GetGenericArguments()));
            }

            if (genericDefinition == typeof(IRdCall <,>))
            {
                return(typeof(RdCall <,>).MakeGenericType(typeInfo.GetGenericArguments()));
            }

            return(typeInfo.AsType());
        }
Beispiel #6
0
        /// <summary>
        /// Register serializer for ValueTuples
        /// </summary>
        private SerializerPair CreateValueTupleSerializer <T>()
        {
            TypeInfo typeInfo = typeof(T).GetTypeInfo();

            ReflectionSerializerVerifier.AssertRoot(typeInfo);

            var argumentTypes = typeInfo.GetGenericArguments();

            var memberGetters = typeInfo.GetFields().Select(ReflectionUtil.GetGetter).ToArray();

            var memberDeserializers = new CtxReadDelegate <object> [argumentTypes.Length];
            var memberSerializers   = new CtxWriteDelegate <object> [argumentTypes.Length];

            for (var index = 0; index < argumentTypes.Length; index++)
            {
                var argumentType = argumentTypes[index];
                var serPair      = GetOrRegisterSerializerInternal(argumentType);
                memberDeserializers[index] = ConvertReader(argumentType, serPair.Reader);
                memberSerializers[index]   = ConvertWriter(argumentType, serPair.Writer);
            }

            var type = typeInfo.AsType();
            CtxReadDelegate <T> readerDelegate = (ctx, unsafeReader) =>
            {
                // todo: consider using IL emit
                var activatorArgs = new object[argumentTypes.Length];
                for (var index = 0; index < argumentTypes.Length; index++)
                {
                    var value = memberDeserializers[index](ctx, unsafeReader);
                    activatorArgs[index] = value;
                }

                var instance = Activator.CreateInstance(type, activatorArgs);
                return((T)instance);
            };

            CtxWriteDelegate <T> writerDelegate = (ctx, unsafeWriter, value) =>
            {
                for (var i = 0; i < argumentTypes.Length; i++)
                {
                    var memberValue = memberGetters[i](value);
                    memberSerializers[i](ctx, unsafeWriter, memberValue);
                }
            };

            return(new SerializerPair(readerDelegate, writerDelegate));
        }
Beispiel #7
0
        private static MethodInfo GetWriteStaticDeserializer([NotNull] TypeInfo typeInfo)
        {
            var types = new[]
            {
                typeof(SerializationCtx),
                typeof(UnsafeWriter),
                typeInfo.AsType(),
            };
            var methodInfo = typeInfo.GetMethod("Write", types, null);

            if (methodInfo == null)
            {
                Assertion.Fail($"Unable to found method in {typeInfo.ToString(true)} with requested signature : public static Write({string.Join(", ", types.Select(t => t.ToString(true)).ToArray())})");
            }

            return(methodInfo);
        }
Beispiel #8
0
        /// <summary>
        /// Register serializers for either <see cref="RdExtAttribute"/> or <see cref="RdModelAttribute"/>
        /// </summary>
        private void RegisterModelSerializer <T>()
        {
            Assertion.Assert(!ReflectionSerializerVerifier.IsScalar(typeof(T)), "Type {0} should be either RdModel or RdExt.", typeof(T));
            // place null marker to detect circular dependencies
            mySerializers.Add(typeof(T), null);

            TypeInfo typeInfo = typeof(T).GetTypeInfo();

            ReflectionSerializerVerifier.AssertRoot(typeInfo);
            var  isScalar      = ReflectionSerializerVerifier.IsScalar(typeInfo);
            bool allowNullable = ReflectionSerializerVerifier.HasRdModelAttribute(typeInfo) || (isScalar && ReflectionSerializerVerifier.CanBeNull(typeInfo));

/*      var intrinsicSerializer = TryGetIntrinsicSerializer(typeInfo);
 *    if (intrinsicSerializer != null)
 *    {
 *      mySerializers[typeof(T)] = intrinsicSerializer;
 *      return;
 *    }*/

            var memberInfos   = SerializerReflectionUtil.GetBindableMembers(typeInfo);
            var memberSetters = memberInfos.Select(ReflectionUtil.GetSetter).ToArray();
            var memberGetters = memberInfos.Select(ReflectionUtil.GetGetter).ToArray();

            // todo: consider using IL emit
            var memberDeserializers = new CtxReadDelegate <object> [memberInfos.Length];
            var memberSerializers   = new CtxWriteDelegate <object> [memberInfos.Length];

            for (var index = 0; index < memberInfos.Length; index++)
            {
                var mi         = memberInfos[index];
                var returnType = ReflectionUtil.GetReturnType(mi);
                var serPair    = GetOrCreateMemberSerializer(mi, serializerType: returnType, allowNullable: allowNullable);
                memberDeserializers[index] = SerializerReflectionUtil.ConvertReader(returnType, serPair.Reader);
                memberSerializers[index]   = SerializerReflectionUtil.ConvertWriter(returnType, serPair.Writer);
            }

            var type = typeInfo.AsType();

            CtxReadDelegate <T> readerDelegate = (ctx, unsafeReader) =>
            {
                if (allowNullable && !unsafeReader.ReadNullness())
                {
                    return(default);
        private static bool IsFieldType(TypeInfo typeInfo, bool canBeArray = true)
        {
            bool IsValidArray()
            {
                if (!typeInfo.IsArray)
                {
                    return(false);
                }
                if (typeInfo.GetArrayRank() != 1)
                {
                    return(false);
                }

                var arrayType = typeInfo.GetElementType().GetTypeInfo();

                return(IsFieldType(arrayType, false));
            }

            return(typeof(IRdBindable).GetTypeInfo().IsAssignableFrom(typeInfo) ||
                   IsPrimitive(typeInfo.AsType()) ||
                   typeInfo.IsEnum ||
                   canBeArray && IsValidArray() ||
                   IsNullable(typeInfo, type => IsPrimitive(type) || type.GetTypeInfo().IsEnum));
        }
Beispiel #10
0
 public static string ToString(this TypeInfo typeInfo, bool fqn)
 {
     return(typeInfo.AsType().ToString(fqn));
 }
Beispiel #11
0
        /// <summary>
        /// Register serializers for either <see cref="RdExtAttribute"/> or <see cref="RdModelAttribute"/>
        /// </summary>
        private void RegisterModelSerializer <T>()
        {
            // place null marker to detect circular dependencies
            mySerializers.Add(typeof(T), null);

            TypeInfo typeInfo = typeof(T).GetTypeInfo();

            ReflectionSerializerVerifier.AssertRoot(typeInfo);
            bool allowNullable = ReflectionSerializerVerifier.HasRdModelAttribute(typeInfo);

            var intrinsicSerializer = TryGetIntrinsicSerializer(typeInfo);

            if (intrinsicSerializer != null)
            {
                mySerializers[typeof(T)] = intrinsicSerializer;
                return;
            }

            var memberInfos   = GetBindableMembers(typeInfo);
            var memberSetters = memberInfos.Select(ReflectionUtil.GetSetter).ToArray();
            var memberGetters = memberInfos.Select(ReflectionUtil.GetGetter).ToArray();

            // todo: consider using IL emit
            var memberDeserializers = new CtxReadDelegate <object> [memberInfos.Length];
            var memberSerializers   = new CtxWriteDelegate <object> [memberInfos.Length];

            for (var index = 0; index < memberInfos.Length; index++)
            {
                var mi         = memberInfos[index];
                var returnType = ReflectionUtil.GetReturnType(mi);
                var serPair    = GetOrCreateMemberSerializer(mi, serializerType: returnType, allowNullable: allowNullable);
                memberDeserializers[index] = ConvertReader(returnType, serPair.Reader);
                memberSerializers[index]   = ConvertWriter(returnType, serPair.Writer);
            }

            var type = typeInfo.AsType();
            CtxReadDelegate <T> readerDelegate = (ctx, unsafeReader) =>
            {
                // todo: support non-default constructors
                var instance = Activator.CreateInstance(type);

                var  bindableInstance = instance as IRdBindable;
                RdId id = default(RdId);
                if (bindableInstance != null)
                {
                    id = unsafeReader.ReadRdId();
                }

                for (var index = 0; index < memberDeserializers.Length; index++)
                {
                    var value = memberDeserializers[index](ctx, unsafeReader);
                    memberSetters[index](instance, value);
                }

                bindableInstance?.WithId(id);

                return((T)instance);
            };

            CtxWriteDelegate <T> writerDelegate = (ctx, unsafeWriter, value) =>
            {
                if (value is IRdBindable bindableInstance)
                {
                    unsafeWriter.Write(bindableInstance.RdId);
                }

                for (var i = 0; i < memberDeserializers.Length; i++)
                {
                    var memberValue = memberGetters[i](value);
                    memberSerializers[i](ctx, unsafeWriter, memberValue);
                }
            };

            mySerializers[type] = new SerializerPair(readerDelegate, writerDelegate);
        }
        public static void AssertValidRdModel([NotNull] TypeInfo type)
        {
            var isDataModel = HasRdModelAttribute(type);

            Assertion.Assert(isDataModel, $"Error in {type.ToString(true)} model: no {nameof(RdModelAttribute)} attribute specified");
            Assertion.Assert(typeof(RdReflectionBindableBase).GetTypeInfo().IsAssignableFrom(type.AsType()), $"Error in {type.ToString(true)} model: should be inherited from {nameof(RdReflectionBindableBase)}");

            // No way to prevent serialization errors for intrinsic serializers, just skip for now
            if (HasIntrinsic(type))
            {
                return;
            }

            foreach (var member in SerializerReflectionUtil.GetBindableMembers(type))
            {
                AssertDataMemberDeclaration(member);
            }
        }
        public static void AssertValidRdExt(TypeInfo type)
        {
            var isRdModel = HasRdExtAttribute(type);

            Assertion.Assert(isRdModel, $"Error in {type.ToString(true)} model: no {nameof(RdExtAttribute)} attribute specified");
            Assertion.Assert(!type.IsValueType, $"Error in {type.ToString(true)} model: can't be ValueType");
            Assertion.Assert(typeof(RdExtReflectionBindableBase).GetTypeInfo().IsAssignableFrom(type.AsType()), $"Error in {type.ToString(true)} model: should be inherited from {nameof(RdExtReflectionBindableBase)}");

            // actually, it is possible, but error-prone.
            // you may have non-rdmodel base class and several sealed derivatives from it.
            // commented sealed check to avoid annoying colleagues.
            // Assertion.Assert(type.IsSealed, $"Error in {type.ToString(true)} model: RdModels must be sealed.");

            foreach (var member in SerializerReflectionUtil.GetBindableMembers(type))
            {
                AssertMemberDeclaration(member);
            }
        }