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 }
internal static Type ToType(TypeInfo typeInfo) { #if (!NETSTANDARD1_3) return(typeInfo); #else return(typeInfo?.AsType()); #endif }
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()); }
/// <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)); }
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); }
/// <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)); }
public static string ToString(this TypeInfo typeInfo, bool fqn) { return(typeInfo.AsType().ToString(fqn)); }
/// <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); } }