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()); }
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()); }
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); }
/// <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);
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); } }
/// <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); }