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);
internal static void FillBindableFields(IReflectionBindable instance) { var type = instance.GetType(); Action <IReflectionBindable> fillBindableFields; lock (ourFillBindableChildren) { ourFillBindableChildren.TryGetValue(type, out fillBindableFields); } if (fillBindableFields == null) { var t = type; var bindableMembers = SerializerReflectionUtil.GetBindableMembers(t.GetTypeInfo()).ToArray(); var getters = bindableMembers.Select(ReflectionUtil.GetGetter).ToArray(); fillBindableFields = (obj) => { for (int i = 0; i < bindableMembers.Length; i++) { var value = getters[i](obj); obj.BindableChildren.Add(new KeyValuePair <string, object>(bindableMembers[i].Name, value)); } }; lock (ourFillBindableChildren) { ourFillBindableChildren[t] = fillBindableFields; } } fillBindableFields(instance); }
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); } }
/// <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 static void PrettyPrint(PrettyPrinter p, IReflectionBindable instance) { Action <IReflectionBindable, PrettyPrinter> prettyPrinter; lock (ourPrettyPrintersLock) { ourPrettyPrinters.TryGetValue(instance.GetType(), out prettyPrinter); } if (prettyPrinter == null) { var t = instance.GetType(); var header = t.Name + " ("; var bindableMembers = SerializerReflectionUtil.GetBindableMembers(t.GetTypeInfo()); var getters = bindableMembers.Select(ReflectionUtil.GetGetter).ToArray(); var intros = bindableMembers.Select(mi => $"{mi.Name} = ").ToArray(); prettyPrinter = (o, printer) => { printer.Print(header); using (printer.IndentCookie()) { for (int i = 0; i < getters.Length; i++) { printer.Print(intros[i]); getters[i](o).PrintEx(printer); printer.Println(); } } printer.Print(")"); }; lock (ourPrettyPrintersLock) { ourPrettyPrinters[t] = prettyPrinter; } } prettyPrinter(instance, p); }
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); }
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); }