예제 #1
0
        private SerializerPair GetOrCreateMemberSerializer([NotNull] MemberInfo mi, [NotNull] Type serializerType, bool allowNullable)
        {
            if (!allowNullable)
            {
                ReflectionSerializerVerifier.AssertMemberDeclaration(mi);
            }
            else
            {
                ReflectionSerializerVerifier.AssertDataMemberDeclaration(mi);
            }

            if (!mySerializers.TryGetValue(serializerType, out var serializerPair))
            {
                serializerPair = GetMemberSerializer(mi, serializerType.GetTypeInfo());
                Assertion.AssertNotNull(serializerPair != null, $"Unable to Create serializer for type {serializerType.ToString(true)}");
                mySerializers[serializerType] = serializerPair;
            }

            if (serializerPair == null)
            {
#if JET_MODE_ASSERT
                Assertion.Fail($"Unable to create serializer for {serializerType.ToString(true)}: circular dependency detected: {string.Join(" -> ", myCurrentSerializersChain.Select(t => Types.ToString(t, true)).ToArray())}");
#endif
                throw new Assertion.AssertionException($"Undetected circular dependency during serializing {serializerType.ToString(true)}");
            }

            return(serializerPair);
        }
예제 #2
0
        private object ActivateRd(Type type)
        {
#if JET_MODE_ASSERT
            Assertion.Assert(!myCurrentActivationChain.Contains(type),
                             $"Unable to activate {type.FullName}: circular dependency detected: {string.Join(" -> ", myCurrentActivationChain.Select(t => t.FullName).ToArray())}");
            myCurrentActivationChain.Enqueue(type);
#endif

            var typeInfo = type.GetTypeInfo();
            ReflectionSerializerVerifier.AssertEitherExtModelAttribute(typeInfo);
            var implementingType = ReflectionSerializerVerifier.GetImplementingType(typeInfo);
            Assertion.Assert(typeof(RdBindableBase).GetTypeInfo().IsAssignableFrom(implementingType),
                             $"Unable to activate {type.FullName}: type should be {nameof(RdBindableBase)}");

            object instance;
            try
            {
                instance = Activator.CreateInstance(implementingType);
            }
            catch (MissingMethodException e)
            {
                throw new MissingMethodException($"Unable to create instance of: {implementingType.ToString(true)}.{e.Message}");
            }

            ReflectionInitInternal(instance);
#if JET_MODE_ASSERT
            myCurrentActivationChain.Dequeue();
#endif
            return(instance);
        }
예제 #3
0
        private object ActivateRdExtMember(MemberInfo mi)
        {
            var returnType       = ReflectionUtil.GetReturnType(mi);
            var typeInfo         = returnType.GetTypeInfo();
            var implementingType = ReflectionSerializerVerifier.GetImplementingType(typeInfo);

            object result;

            if (implementingType.GetTypeInfo().IsGenericType)
            {
                result = ActivateGenericMember(mi.Name, typeInfo);
            }
            else
            {
                result = ActivateRd(returnType);
            }

            if (result is IRdReactive activatedBindable)
            {
                foreach (var _ in mi.GetCustomAttributes(typeof(RdAsyncAttribute), false))
                {
                    activatedBindable.Async = true;
                }
            }

            return(result);
        }
예제 #4
0
        private SerializerPair CreateCustomScalar <T>()
        {
            if (typeof(IRdBindable).IsAssignableFrom(typeof(T)))
            {
                Assertion.Fail($"Invalid scalar type: {typeof(T).ToString(true)}. Scalar types cannot be IRdBindable.");
            }
            if (typeof(T).IsInterface || typeof(T).IsAbstract)
            {
                Assertion.Fail($"Invalid scalar type: {typeof(T).ToString(true)}. Scalar types should be concrete types.");
            }

            TypeInfo typeInfo      = typeof(T).GetTypeInfo();
            var      allowNullable = ReflectionSerializerVerifier.CanBeNull(typeInfo);

            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];

            CtxReadDelegate <T> readerDelegate = (ctx, unsafeReader) =>
            {
                if (allowNullable && !unsafeReader.ReadNullness())
                {
                    return(default);
예제 #5
0
        private SerializerPair TryGetIntrinsicSerializer(TypeInfo typeInfo)
        {
            if (!ReflectionSerializerVerifier.HasIntrinsicMethods(typeInfo))
            {
                return(null);
            }

            var genericArguments = typeInfo.GetGenericArguments();

            if (genericArguments.Length == 1)
            {
                var argument    = genericArguments[0];
                var staticRead  = GetReadStaticSerializer(typeInfo, argument);
                var staticWrite = GetWriteStaticDeserializer(typeInfo);
                return(SerializerPair.CreateFromMethods(staticRead, staticWrite, GetOrRegisterSerializerInternal(argument)));
            }

            if (genericArguments.Length == 0)
            {
                var staticRead  = GetReadStaticSerializer(typeInfo);
                var staticWrite = GetWriteStaticDeserializer(typeInfo);
                return(SerializerPair.CreateFromMethods(staticRead, staticWrite));
            }

            return(null);
        }
예제 #6
0
        private object ActivateGenericMember(string memberName, TypeInfo memberType)
        {
            var implementingType  = ReflectionSerializerVerifier.GetImplementingType(memberType);
            var genericDefinition = implementingType.GetGenericTypeDefinition();

            var genericArguments = implementingType.GetTypeInfo().GetGenericArguments();
            var argument         = genericArguments[0];
            var serializerPair   = GetProperSerializer(argument);

            if (genericDefinition == typeof(RdProperty <>) ||
                genericDefinition == typeof(RdSignal <>) ||
                genericDefinition == typeof(RdSet <>))
            {
                return(Activator.CreateInstance(implementingType, serializerPair.Reader, serializerPair.Writer));
            }

            if (genericDefinition == typeof(RdList <>))
            {
                return(Activator.CreateInstance(implementingType, serializerPair.Reader, serializerPair.Writer, 1L /*nextVersion*/));
            }

            if (genericDefinition == typeof(RdMap <,>) || genericDefinition == typeof(InprocRpc <,>) || genericDefinition == typeof(RdCall <,>) || genericDefinition == typeof(RdCall <,>))
            {
                var argument2       = genericArguments[1];
                var serializerPair2 = GetProperSerializer(argument2);
                var instance        = Activator.CreateInstance(implementingType, serializerPair.Reader, serializerPair.Writer, serializerPair2.Reader, serializerPair2.Writer);
                if (ourLog.IsTraceEnabled())
                {
                    ourLog.Trace("Create RdCall: {0}.{1}, TReq poly: {2}, TRes poly: {3}", implementingType.FullName, memberName, serializerPair.IsPolymorphic, serializerPair2.IsPolymorphic);
                }
                ((RdReactiveBase)instance).ValueCanBeNull = true;
                return(instance);
            }

            if (genericDefinition == typeof(Nullable <>))
            {
                // already initialized to null
                return(null);
            }

            // hack for UProperty & USignal
            if (genericArguments.Length == 1 &&
                (typeof(IViewableProperty <>).MakeGenericType(genericArguments).GetTypeInfo().IsAssignableFrom(implementingType) ||
                 typeof(ISignal <>).MakeGenericType(genericArguments).GetTypeInfo().IsAssignableFrom(implementingType)
                ))
            {
                foreach (var ctor in implementingType.GetTypeInfo().GetConstructors(BindingFlags.Public | BindingFlags.Instance))
                {
                    var parameters = ctor.GetParameters();
                    if (parameters.Length == 3 && parameters[0].Name == "id")
                    {
                        return(Activator.CreateInstance(implementingType, memberName, serializerPair.Reader, serializerPair.Writer));
                    }
                }
            }

            throw new Exception($"Unable to activate generic type: {memberType}");
        }
예제 #7
0
        /// <summary>
        /// Return static serializers for type
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public SerializerPair GetOrCreate(Type type)
        {
            if (myStaticSerializers.TryGetValue(type, out var pair))
            {
                return(pair);
            }

            var result = CreateSerializer(type);

            myStaticSerializers[type] = result;
            return(result);

            SerializerPair CreateSerializer(Type t)
            {
                var typeInfo = t.GetTypeInfo();

                var intrinsic = TryGetIntrinsicSerializer(typeInfo);

                if (intrinsic != null)
                {
                    myTypesCatalog.AddType(type);
                    return(intrinsic);
                }

                if (IsList(t))
                {
                    var genericTypeArgument        = t.GetGenericArguments()[0];
                    var argumentTypeSerializerPair = GetInstanceSerializer(genericTypeArgument);
                    return((SerializerPair)ReflectionUtil.InvokeStaticGeneric(typeof(CollectionSerializers), nameof(CollectionSerializers.CreateListSerializerPair), genericTypeArgument, argumentTypeSerializerPair));
                }
                else if (t.IsArray)
                {
                    return((SerializerPair)ReflectionUtil.InvokeGenericThis(this, nameof(CreateArraySerializer), t.GetElementType()));
                }
                else if (t.IsEnum)
                {
                    var serializer = ReflectionUtil.InvokeGenericThis(this, nameof(CreateEnumSerializer), t);
                    return((SerializerPair)serializer);
                }
                else if (ReflectionSerializerVerifier.IsValueTuple(typeInfo))
                {
                    return((SerializerPair)ReflectionUtil.InvokeGenericThis(this, nameof(CreateValueTupleSerializer), type));
                }
                else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    var genericTypeArgument = typeInfo.GetGenericArguments()[0];
                    var nullableSerializer  = (SerializerPair)ReflectionUtil.InvokeGenericThis(this, nameof(RegisterNullable), genericTypeArgument);
                    return(nullableSerializer);
                    // return CreateGenericSerializer(member, typeInfo, implementingType, implementingTypeInfo);
                }
                else
                {
                    myTypesCatalog.AddType(type);
                    var serializer = ReflectionUtil.InvokeGenericThis(this, nameof(CreateCustomScalar), t);
                    return((SerializerPair)serializer);
                }
            }
        }
예제 #8
0
        internal static FieldInfo[] GetBindableMembers(TypeInfo typeInfo)
        {
/*
 *    var rpcInterface = GetRpcInterface();
 *    if (rpcInterface != null)
 *    {
 *      var rpcInterfaceMap = typeInfo.GetInterfaceMap(rpcInterface);
 *      //members = rpcInterfaceMap.TargetMethods;
 *    }
 */
            Type baseType;

            if (ReflectionSerializerVerifier.HasRdExtAttribute(typeInfo))
            {
                baseType = typeof(RdExtReflectionBindableBase);
            }
            else if (ReflectionSerializerVerifier.HasRdModelAttribute(typeInfo))
            {
                baseType = typeof(RdReflectionBindableBase);
            }
            else
            {
                baseType = typeof(RdBindableBase);
            }

            bool isRdExtImpl      = baseType == typeof(RdExtReflectionBindableBase) && !typeInfo.GetInterfaces().Contains(typeof(IProxyTypeMarker));
            bool isRdRpcInterface = typeInfo.IsInterface; // can be specified in RdExt // && typeInfo.GetCustomAttribute<RdRpcAttribute>() != null;

            var fields = GetFields(typeInfo, baseType);
            var list   = new List <FieldInfo>();

            foreach (var mi in fields)
            {
                if (typeof(RdExtReflectionBindableBase).IsAssignableFrom(mi.FieldType))
                {
                    continue;
                }

                if (
                    mi.MemberType == MemberTypes.Field &&
                    (mi.DeclaringType != null && !mi.DeclaringType.GetTypeInfo().IsAssignableFrom(baseType)) &&
                    mi.GetCustomAttribute <NonSerializedAttribute>() == null &&

                    // arbitrary data is allowed in RdExt implementations since they don't have to be serializable
                    !(isRdExtImpl && ReflectionSerializerVerifier.IsScalar(ReflectionSerializerVerifier.GetImplementingType(mi.FieldType.GetTypeInfo())))
                    )
                {
                    list.Add(mi);
                }
                else if (isRdRpcInterface)
                {
                    throw new Exception($"Invalid member in RdRpc interface: {typeInfo.ToString(true)}.{mi.Name}");
                }
            }

            return(list.ToArray());
        }
예제 #9
0
        private object ActivateGenericMember(string memberName, TypeInfo memberType)
        {
            var implementingType  = ReflectionSerializerVerifier.GetImplementingType(memberType);
            var genericDefinition = implementingType.GetGenericTypeDefinition();

            var genericArguments = implementingType.GetTypeInfo().GetGenericArguments();
            var argument         = genericArguments[0];
            var serializerPair   = GetProperSerializer(argument);

            if (genericDefinition == typeof(RdProperty <>) ||
                genericDefinition == typeof(RdSignal <>) ||
                genericDefinition == typeof(RdList <>) ||
                genericDefinition == typeof(RdSet <>))
            {
                return(Activator.CreateInstance(implementingType, serializerPair.Reader, serializerPair.Writer));
            }

            if (genericDefinition == typeof(RdMap <,>))
            {
                var argument2       = genericArguments[1];
                var serializerPair2 = GetProperSerializer(argument2);
                return(Activator.CreateInstance(implementingType, serializerPair.Reader, serializerPair.Writer, serializerPair2.Reader, serializerPair2.Writer));
            }

            if (genericDefinition == typeof(InprocRpc <,>))
            {
                var rpcResultType = genericArguments[1];
                GetProperSerializer(rpcResultType);
                return(Activator.CreateInstance(implementingType));
            }

            if (genericDefinition == typeof(Nullable <>))
            {
                // already initialized to null
                return(null);
            }

            // hack for UProperty
            if (genericArguments.Length == 1 &&
                typeof(IViewableProperty <>).MakeGenericType(genericArguments).GetTypeInfo().IsAssignableFrom(implementingType))
            {
                foreach (var ctor in implementingType.GetTypeInfo().GetConstructors(BindingFlags.Public | BindingFlags.Instance))
                {
                    var parameters = ctor.GetParameters();
                    if (parameters.Length == 3 && parameters[0].Name == "id")
                    {
                        return(Activator.CreateInstance(implementingType, memberName, serializerPair.Reader, serializerPair.Writer));
                    }
                }
            }

            throw new Exception($"Unable to activate generic type: {memberType}");
        }
예제 #10
0
        public Type CreateType <TInterface>() where TInterface : class
        {
            if (!typeof(TInterface).IsInterface)
            {
                throw new ArgumentException("Only interfaces are supported.");
            }

            if (typeof(TInterface).GetGenericArguments().Length > 0)
            {
                throw new ArgumentException("Generic interfaces are not supported.");
            }

            if (!ReflectionSerializerVerifier.IsRpcAttributeDefined(typeof(TInterface)))
            {
                throw new ArgumentException($"Unable to create proxy for {typeof(TInterface)}. No {nameof(RdRpcAttribute)} specified.");
            }

            var moduleBuilder = myModuleBuilder.Value;
            var className     = typeof(TInterface).Name.Substring(1);
            var proxyTypeName = "Proxy." + className;
            var typebuilder   = moduleBuilder.DefineType(
                proxyTypeName,
                TypeAttributes.NotPublic | TypeAttributes.Class | TypeAttributes.Sealed,
                typeof(RdExtReflectionBindableBase));

            // Implement interface
            typebuilder.AddInterfaceImplementation(typeof(TInterface));

            // mark it as proxy type
            typebuilder.AddInterfaceImplementation(typeof(IProxyTypeMarker));

            // Add RdExt attribute to type
            var rdExtConstructor = typeof(RdExtAttribute).GetConstructors()[0];

            typebuilder.SetCustomAttribute(new CustomAttributeBuilder(rdExtConstructor, new object[0]));

            var memberNames = new HashSet <string>(StringComparer.Ordinal);
            var members     = typeof(TInterface).GetMembers(BindingFlags.Instance | BindingFlags.Public);

            foreach (var member in members)
            {
                if (!memberNames.Add(member.Name))
                {
                    throw new ArgumentException($"Duplicate member name: {member.Name}. Method overloads are not supported.");
                }
                ImplementMember <TInterface>(typebuilder, member);
            }
#if NET35
            return(typebuilder.CreateType());
#else
            return(typebuilder.CreateTypeInfo());
#endif
        }
예제 #11
0
        public static Type GetRpcInterface(TypeInfo typeInfo)
        {
            foreach (var @interface in typeInfo.GetInterfaces())
            {
                if (ReflectionSerializerVerifier.IsRpcAttributeDefined(@interface))
                {
                    return(@interface);
                }
            }

            return(null);
        }
예제 #12
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));
        }
예제 #13
0
        private SerializerPair GetOrRegisterStaticSerializerInternal(Type type, bool instance)
        {
            if (ReflectionSerializerVerifier.IsScalar(type))
            {
                return(GetOrCreateScalar(type, instance));
            }

            // RdModels only
            if (!mySerializers.TryGetValue(type, out var serializerPair))
            {
#if JET_MODE_ASSERT
                myCurrentSerializersChain.Enqueue(type);
#endif

                using (new FirstChanceExceptionInterceptor.ThreadLocalDebugInfo(type))
                {
                    if (ReflectionSerializerVerifier.HasIntrinsicFields(type.GetTypeInfo()))
                    {
                        mySerializers.Add(type, Intrinsic.TryGetIntrinsicSerializer(
                                              type.GetTypeInfo(),
                                              _ => throw new InvalidOperationException("Generic models are not supported")));
                    }
                    else
                    {
                        ReflectionUtil.InvokeGenericThis(this, nameof(RegisterModelSerializer), type);
                    }
                }

#if JET_MODE_ASSERT
                myCurrentSerializersChain.Dequeue();
#endif

                if (!mySerializers.TryGetValue(type, out serializerPair))
                {
                    throw new KeyNotFoundException($"Unable to register type {type.ToString(true)}: serializer can't be found");
                }
            }

            Assertion.AssertNotNull(serializerPair, $"Unable to register type: {type.ToString(true)}, undetected circular dependency.");

            if (instance && !type.IsSealed)
            {
                return(GetPolymorphic(type));
            }

            return(serializerPair);
        }
예제 #14
0
        internal static FieldInfo[] GetBindableMembers(TypeInfo typeInfo)
        {
/*
 *    var rpcInterface = GetRpcInterface();
 *    if (rpcInterface != null)
 *    {
 *      var rpcInterfaceMap = typeInfo.GetInterfaceMap(rpcInterface);
 *      //members = rpcInterfaceMap.TargetMethods;
 *    }
 */
            Type baseType;

            if (ReflectionSerializerVerifier.HasRdExtAttribute(typeInfo))
            {
                baseType = typeof(RdExtReflectionBindableBase);
            }
            else if (ReflectionSerializerVerifier.HasRdModelAttribute(typeInfo))
            {
                baseType = typeof(RdReflectionBindableBase);
            }
            else
            {
                baseType = typeof(RdBindableBase);
            }

            bool isRdExt = baseType == typeof(RdExtReflectionBindableBase);

            var members = GetFields(typeInfo, baseType);
            var list    = new List <FieldInfo>();

            foreach (var mi in members)
            {
                if (
                    mi.MemberType == MemberTypes.Field &&
                    (mi.DeclaringType != null && !mi.DeclaringType.GetTypeInfo().IsAssignableFrom(baseType)) &&
                    mi.GetCustomAttribute <NonSerializedAttribute>() == null &&

                    // arbitrary data is allowed in RdExt since they don't have to be serializable
                    !(isRdExt && ReflectionSerializerVerifier.IsScalar(ReflectionSerializerVerifier.GetImplementingType(mi.FieldType.GetTypeInfo())))
                    )
                {
                    list.Add(mi);
                }
            }

            return(list.ToArray());
        }
예제 #15
0
        public static Type GetRpcInterface(TypeInfo typeInfo)
        {
            if (typeInfo.GetCustomAttribute <RdExtAttribute>() is RdExtAttribute rdExt && rdExt.RdRpcInterface != null)
            {
                return(rdExt.RdRpcInterface);
            }

            foreach (var @interface in typeInfo.GetInterfaces())
            {
                if (ReflectionSerializerVerifier.IsRpcAttributeDefined(@interface))
                {
                    return(@interface);
                }
            }

            return(null);
        }
예제 #16
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);
예제 #17
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);
        }
예제 #18
0
        internal static MemberInfo[] GetBindableMembers(TypeInfo typeInfo)
        {
            ReflectionSerializerVerifier.AssertEitherExtModelAttribute(typeInfo);

            var list = new List <MemberInfo>();

            foreach (var mi in typeInfo.GetMembers(BindingFlags.Public | BindingFlags.Instance))
            {
                if ((mi.MemberType == MemberTypes.Property && ReflectionUtil.TryGetSetter(mi) != null) ||
                    mi.MemberType == MemberTypes.Field)
                {
                    if (mi.DeclaringType != null && !mi.DeclaringType.GetTypeInfo().IsAssignableFrom(typeof(RdReflectionBindableBase)))
                    {
                        list.Add(mi);
                    }
                }
            }

            return(list.ToArray());
        }
예제 #19
0
        private object ActivateRdExtMember(MemberInfo mi)
        {
            var returnType       = ReflectionUtil.GetReturnType(mi);
            var typeInfo         = returnType.GetTypeInfo();
            var implementingType = ReflectionSerializerVerifier.GetImplementingType(typeInfo);

            object result;

            if (implementingType.GetTypeInfo().IsGenericType)
            {
                result = ActivateGenericMember(mi.Name, typeInfo);
            }
            else
            {
                result = ActivateRd(returnType);
            }

            SetAsync(mi, result);

            return(result);
        }
예제 #20
0
        private object ActivateRd(Type type)
        {
#if JET_MODE_ASSERT
            Assertion.Assert(!myCurrentActivationChain.Contains(type),
                             $"Unable to activate {type.FullName}: circular dependency detected: {string.Join(" -> ", myCurrentActivationChain.Select(t => t.FullName).ToArray())}");
            myCurrentActivationChain.Enqueue(type);
#endif

            var typeInfo = type.GetTypeInfo();
            ReflectionSerializerVerifier.AssertValidRdExt(typeInfo);
            var implementingType = ReflectionSerializerVerifier.GetImplementingType(typeInfo);
            Assertion.Assert(typeof(IRdBindable).GetTypeInfo().IsAssignableFrom(implementingType),
                             $"Unable to activate {type.FullName}: type should be {nameof(IRdBindable)}");

            var instance             = Activator.CreateInstance(implementingType);
            var implementingTypeInfo = implementingType.GetTypeInfo();

            foreach (var mi in ReflectionSerializers.GetBindableMembers(implementingTypeInfo))
            {
                ReflectionSerializerVerifier.AssertMemberDeclaration(mi);
                var currentValue = ReflectionUtil.GetGetter(mi)(instance);
                if (currentValue == null)
                {
                    currentValue = ActivateRdExtMember(mi);

                    var memberSetter = ReflectionUtil.GetSetter(mi);
                    memberSetter(instance, currentValue);
                }
            }
#if JET_MODE_ASSERT
            myCurrentActivationChain.Dequeue();
#endif
            // Allow initialize to setup bindings to composite properties.
            if (instance is RdReflectionBindableBase reflectionBindable)
            {
                reflectionBindable.OnActivated();
            }

            return(instance);
        }
예제 #21
0
        internal SerializerPair GetOrCreateMemberSerializer([NotNull] MemberInfo mi, [NotNull] Type serializerType, bool allowNullable)
        {
            if (!allowNullable)
            {
                ReflectionSerializerVerifier.AssertMemberDeclaration(mi);
            }
            else
            {
                ReflectionSerializerVerifier.AssertDataMemberDeclaration(mi);
            }

            var typeInfo             = serializerType.GetTypeInfo();
            var implementingType     = ReflectionSerializerVerifier.GetImplementingType(typeInfo);
            var implementingTypeInfo = implementingType.GetTypeInfo();

            if (typeInfo.IsGenericType && !(ReflectionSerializerVerifier.HasRdModelAttribute(typeInfo) || ReflectionSerializerVerifier.HasRdExtAttribute(typeInfo)))
            {
                return(CreateGenericSerializer(mi, typeInfo, implementingType));
            }
            else if (ReflectionSerializerVerifier.IsScalar(serializerType))
            {
                return(GetOrCreateScalar(serializerType, false));
            }
            else
            {
                var serializerPair = GetOrRegisterStaticSerializerInternal(serializerType, false);
                Assertion.AssertNotNull(serializerPair != null, $"Unable to Create serializer for type {serializerType.ToString(true)}");
                if (serializerPair == null)
                {
#if JET_MODE_ASSERT
                    Assertion.Fail($"Unable to create serializer for {serializerType.ToString(true)}: circular dependency detected: {String.Join(" -> ", myCurrentSerializersChain.Select(t => t.ToString(true)).ToArray())}");
#endif
                    throw new Assertion.AssertionException($"Undetected circular dependency during serializing {serializerType.ToString(true)}");
                }

                return(serializerPair);
            }
        }
예제 #22
0
        private SerializerPair GetOrRegisterStaticSerializerInternal(Type type, bool instance)
        {
            if (!mySerializers.TryGetValue(type, out var serializerPair))
            {
#if JET_MODE_ASSERT
                myCurrentSerializersChain.Enqueue(type);
#endif

                if (ReflectionSerializerVerifier.IsScalar(type))
                {
                    return(GetOrCreateScalar(type, instance));
                }
                else
                {
                    ReflectionUtil.InvokeGenericThis(this, nameof(RegisterModelSerializer), type);
                }


#if JET_MODE_ASSERT
                myCurrentSerializersChain.Dequeue();
#endif

                if (!mySerializers.TryGetValue(type, out serializerPair))
                {
                    throw new KeyNotFoundException($"Unable to register type {type.ToString(true)}: serializer can't be found");
                }
            }

            Assertion.AssertNotNull(serializerPair, $"Unable to register type: {type.ToString(true)}, undetected circular dependency.");

            if (instance && CanBePolymorphicRdModel(type))
            {
                return(GetPolymorphic(type));
            }

            return(serializerPair);
        }
예제 #23
0
 private SerializerPair GetPrimitiveSerializer <T>()
 {
     Assertion.Assert(ReflectionSerializerVerifier.IsPrimitive(typeof(T)), $"{typeof(T).ToString(true)} expected to be primitive type");
     return(mySerializers[typeof(T)]);
 }
예제 #24
0
        private object ReflectionInitInternal(object instance)
        {
            var typeInfo = instance.GetType().GetTypeInfo();

            if (ReflectionSerializerVerifier.HasRdExtAttribute(instance.GetType().GetTypeInfo()))
            {
                ReflectionSerializerVerifier.AssertValidRdExt(typeInfo);
            }

            foreach (var mi in SerializerReflectionUtil.GetBindableMembers(typeInfo))
            {
                ReflectionSerializerVerifier.AssertMemberDeclaration(mi);
                var currentValue = ReflectionUtil.GetGetter(mi)(instance);
                if (currentValue == null)
                {
                    currentValue = ActivateRdExtMember(mi);

                    var memberSetter = ReflectionUtil.GetSetter(mi);
                    memberSetter(instance, currentValue);
                }
                else
                {
                    var implementingType = ReflectionSerializerVerifier.GetImplementingType(ReflectionUtil.GetReturnType(mi).GetTypeInfo());
                    Assertion.Assert(currentValue.GetType() == implementingType,
                                     "Bindable field {0} was initialized with incompatible type. Expected type {1}, actual {2}",
                                     mi,
                                     implementingType.ToString(true),
                                     currentValue.GetType().ToString(true));
                }
            }

            // Add RdEndpoint for Impl class (counterpart of Proxy)
            var  interfaces   = typeInfo.GetInterfaces();
            bool isProxy      = interfaces.Contains(typeof(IProxyTypeMarker));
            var  rpcInterface = ReflectionSerializersFactory.GetRpcInterface(typeInfo);

            if (!isProxy && rpcInterface != null)
            {
                var bindableChildren = ((IReflectionBindable)instance).BindableChildren;

                var interfaceMap     = typeInfo.GetInterfaceMap(rpcInterface);
                var interfaceMethods = interfaceMap.InterfaceMethods;

                // Dynamic adapters for Properties are not required, so skip them
                var ignoreMethods = new HashSet <string>(StringComparer.Ordinal);
                foreach (var propertyInfo in rpcInterface.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    ignoreMethods.Add(propertyInfo.GetSetMethod()?.Name);
                    ignoreMethods.Add(propertyInfo.GetGetMethod()?.Name);
                }

                foreach (var interfaceMethod in interfaceMethods)
                {
                    if (ignoreMethods.Contains(interfaceMethod.Name))
                    {
                        continue;
                    }

                    var adapter = myProxyGenerator.CreateAdapter(rpcInterface, interfaceMethod);

                    var name        = ProxyGenerator.ProxyFieldName(interfaceMethod);
                    var requestType = ProxyGenerator.GetRequstType(interfaceMethod)[0];
                    EnsureFakeTupleRegistered(requestType);

                    var responseNonTaskType = ProxyGenerator.GetResponseType(interfaceMethod, unwrapTask: true);
                    var responseType        = ProxyGenerator.GetResponseType(interfaceMethod, unwrapTask: false);
                    var endPointType        = typeof(RdCall <,>).MakeGenericType(requestType, responseNonTaskType);
                    var endpoint            = ActivateGenericMember(name, endPointType.GetTypeInfo());
                    SetAsync(interfaceMethod, endpoint);
                    if (endpoint is RdReactiveBase reactiveBase)
                    {
                        reactiveBase.ValueCanBeNull = true;
                    }
                    if (ProxyGenerator.IsSync(interfaceMethod))
                    {
                        var delType    = typeof(Func <, ,>).MakeGenericType(typeof(Lifetime), requestType, typeof(RdTask <>).MakeGenericType(responseNonTaskType));
                        var @delegate  = adapter.CreateDelegate(delType, instance);
                        var methodInfo = typeof(ReflectionRdActivator).GetMethod(nameof(SetHandler)).NotNull().MakeGenericMethod(requestType, responseNonTaskType);
                        methodInfo.Invoke(null, new[] { endpoint, @delegate });
                    }
                    else
                    {
                        if (responseType == typeof(Task))
                        {
                            var delType    = typeof(Func <, ,>).MakeGenericType(typeof(Lifetime), requestType, typeof(Task));
                            var @delegate  = adapter.CreateDelegate(delType, instance);
                            var methodInfo = typeof(ReflectionRdActivator).GetMethod(nameof(SetHandlerTaskVoid)).NotNull().MakeGenericMethod(requestType);
                            methodInfo.Invoke(null, new[] { endpoint, @delegate });
                        }
                        else
                        {
                            var delType    = typeof(Func <, ,>).MakeGenericType(typeof(Lifetime), requestType, typeof(Task <>).MakeGenericType(responseNonTaskType));
                            var @delegate  = adapter.CreateDelegate(delType, instance);
                            var methodInfo = typeof(ReflectionRdActivator).GetMethod(nameof(SetHandlerTask)).NotNull().MakeGenericMethod(requestType, responseNonTaskType);
                            methodInfo.Invoke(null, new[] { endpoint, @delegate });
                        }
                    }

                    bindableChildren.Add(new KeyValuePair <string, object>(name, endpoint));
                }
            }
            else if (rpcInterface != null)
            {
                foreach (var interfaceMethod in rpcInterface.GetMethods())
                {
                    var requestType = ProxyGenerator.GetRequstType(interfaceMethod)[0];
                    EnsureFakeTupleRegistered(requestType);
                }
            }

            // Allow initialize to setup bindings to composite properties.
            if (instance is IReflectionBindable reflectionBindable)
            {
                reflectionBindable.OnActivated();
            }

            return(instance);
        }
예제 #25
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);
        }
예제 #26
0
        /// <summary>
        /// Return static serializers for type
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public SerializerPair GetOrCreate(Type type)
        {
            if (myStaticSerializers.TryGetValue(type, out var pair))
            {
                return(pair);
            }

            if (myBlackListChecker(type))
            {
                Assertion.Fail($"Attempt to create serializer for black-listed type: {type.ToString(true)}");
            }

            var result = CreateSerializer(type);

            myStaticSerializers[type] = result;
            return(result);

            SerializerPair CreateSerializer(Type t)
            {
                var typeInfo = t.GetTypeInfo();

                var intrinsic = Intrinsic.TryGetIntrinsicSerializer(typeInfo, GetInstanceSerializer);

                if (intrinsic != null)
                {
                    myTypesCatalog.AddType(type);
                    return(intrinsic);
                }

                if (IsList(t))
                {
                    var genericTypeArgument        = t.GetGenericArguments()[0];
                    var argumentTypeSerializerPair = GetInstanceSerializer(genericTypeArgument);
                    return((SerializerPair)ReflectionUtil.InvokeStaticGeneric(typeof(CollectionSerializers), nameof(CollectionSerializers.CreateListSerializerPair), genericTypeArgument, argumentTypeSerializerPair));
                }
                else if (IsDictionary(t) || IsReadOnlyDictionary(t))
                {
                    var typeArguments          = t.GetGenericArguments();
                    var tkey                   = typeArguments[0];
                    var tvalue                 = typeArguments[1];
                    var keySerializer          = GetInstanceSerializer(tkey);
                    var valueSerializer        = GetInstanceSerializer(tvalue);
                    var serializersFactoryName = IsReadOnlyDictionary(t) ? nameof(CollectionSerializers.CreateReadOnlyDictionarySerializerPair) : nameof(CollectionSerializers.CreateDictionarySerializerPair);
                    return((SerializerPair)ReflectionUtil.InvokeStaticGeneric2(typeof(CollectionSerializers), serializersFactoryName, tkey, tvalue, keySerializer, valueSerializer));
                }
                else if (t.IsArray)
                {
                    return((SerializerPair)ReflectionUtil.InvokeGenericThis(this, nameof(CreateArraySerializer), t.GetElementType()));
                }
                else if (t.IsEnum)
                {
                    var serializer = ReflectionUtil.InvokeGenericThis(this, nameof(CreateEnumSerializer), t);
                    return((SerializerPair)serializer);
                }
                else if (ReflectionSerializerVerifier.IsValueTuple(typeInfo))
                {
                    return((SerializerPair)ReflectionUtil.InvokeGenericThis(this, nameof(CreateValueTupleSerializer), type));
                }
                else if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    var genericTypeArgument = typeInfo.GetGenericArguments()[0];
                    var nullableSerializer  = (SerializerPair)ReflectionUtil.InvokeGenericThis(this, nameof(RegisterNullable), genericTypeArgument);
                    return(nullableSerializer);
                    // return CreateGenericSerializer(member, typeInfo, implementingType, implementingTypeInfo);
                }
                else
                {
                    myTypesCatalog.AddType(type);
                    var serializer = ReflectionUtil.InvokeGenericThis(this, nameof(CreateCustomScalar), t);
                    return((SerializerPair)serializer);
                }
            }
        }
예제 #27
0
파일: Intrinsic.cs 프로젝트: Tryweirder/rd
        public static SerializerPair TryGetIntrinsicSerializer(TypeInfo typeInfo, Func <Type, SerializerPair> getInstanceSerializer)
        {
            if (ReflectionSerializerVerifier.HasIntrinsicNonProtocolMethods(typeInfo))
            {
                var genericArguments = typeInfo.GetGenericArguments();

                /*
                 * if (genericArguments.Length == 1)
                 * {
                 * var argument = genericArguments[0];
                 * var staticRead = SerializerReflectionUtil.GetReadStaticSerializer(typeInfo, argument);
                 * var staticWrite = SerializerReflectionUtil.GetWriteStaticDeserializer(typeInfo);
                 * return SerializerPair.CreateFromMethods(staticRead, staticWrite, getInstanceSerializer(argument));
                 * }
                 */
                if (genericArguments.Length == 0)
                {
                    var staticRead     = SerializerReflectionUtil.GetReadStaticNonProtocolSerializer(typeInfo);
                    var instanceWriter = SerializerReflectionUtil.GetWriteNonProtocolDeserializer(typeInfo);
                    return(SerializerPair.CreateFromNonProtocolMethods(staticRead, instanceWriter));
                }

                return(null);
            }

            if (ReflectionSerializerVerifier.HasIntrinsicProtocolMethods(typeInfo))
            {
                var genericArguments = typeInfo.GetGenericArguments();
                if (genericArguments.Length == 1)
                {
                    var argument    = genericArguments[0];
                    var staticRead  = SerializerReflectionUtil.GetReadStaticSerializer(typeInfo, argument);
                    var staticWrite = SerializerReflectionUtil.GetWriteStaticDeserializer(typeInfo);
                    return(SerializerPair.CreateFromMethods(staticRead, staticWrite, getInstanceSerializer(argument)));
                }

                if (genericArguments.Length == 0)
                {
                    var staticRead  = SerializerReflectionUtil.GetReadStaticSerializer(typeInfo);
                    var staticWrite = SerializerReflectionUtil.GetWriteStaticDeserializer(typeInfo);
                    return(SerializerPair.CreateFromMethods(staticRead, staticWrite));
                }

                return(null);
            }
            else if (ReflectionSerializerVerifier.HasIntrinsicFields(typeInfo))
            {
                var readField  = typeInfo.GetField("Read", BindingFlags.Public | BindingFlags.Static);
                var writeField = typeInfo.GetField("Write", BindingFlags.Public | BindingFlags.Static);
                if (readField == null)
                {
                    Assertion.Fail($"Invalid intrinsic serializer for type {typeInfo}. Static field 'Read' with type {typeof(CtxReadDelegate<>).ToString(true)} not found");
                }
                if (writeField == null)
                {
                    Assertion.Fail($"Invalid intrinsic serializer for type {typeInfo}. Static field 'Write' with type {typeof(CtxWriteDelegate<>).ToString(true)} not found");
                }
                var reader = readField.GetValue(null);
                var writer = writeField.GetValue(null);
                return(new SerializerPair(reader, writer));
            }
            else if (ReflectionSerializerVerifier.HasIntrinsicAttribute(typeInfo))
            {
                var marshallerType = typeInfo.GetCustomAttribute <RdScalarAttribute>().NotNull().Marshaller;
                var marshaller     = Activator.CreateInstance(marshallerType);
                return((SerializerPair)ReflectionUtil.InvokeStaticGeneric(typeof(SerializerPair), nameof(SerializerPair.FromMarshaller), typeInfo, marshaller));
            }

            return(null);
        }