private static bool LinkDecoderAsObject <TEntity>(IDecoderDescriptor <TEntity> descriptor, BindingFlags bindings, Type type, string name, object setter, IDictionary <Type, object> parents) { var constructor = MethodResolver .Create <Func <object> >(() => ConstructorGenerator.CreateConstructor <object>()) .SetGenericArguments(type) .Invoke(null); if (parents.TryGetValue(type, out var parent)) { MethodResolver .Create <Func <IDecoderDescriptor <TEntity>, string, Func <object>, Setter <TEntity, object>, IDecoderDescriptor <object>, IDecoderDescriptor <object> > >((d, n, c, s, p) => d.HasField(n, c, s, p)) .SetGenericArguments(type) .Invoke(descriptor, name, constructor, setter, parent); return(true); } var fieldDescriptor = MethodResolver .Create <Func <IDecoderDescriptor <TEntity>, string, Func <object>, Setter <TEntity, object>, IDecoderDescriptor <object> > >((d, n, c, s) => d.HasField(n, c, s)) .SetGenericArguments(type) .Invoke(descriptor, name, constructor, setter); var result = MethodResolver .Create <Func <IDecoderDescriptor <object>, BindingFlags, Dictionary <Type, object>, bool> >((d, f, p) => Linker.LinkDecoder(d, f, p)) .SetGenericArguments(type) .Invoke(null, fieldDescriptor, bindings, parents); return(result is bool success && success); }
private static bool LinkEncoderAsObject <TEntity>(IEncoderDescriptor <TEntity> descriptor, BindingFlags bindings, Type type, string name, object getter, IDictionary <Type, object> parents) { if (parents.TryGetValue(type, out var recurse)) { MethodResolver .Create <Func <IEncoderDescriptor <TEntity>, string, Func <TEntity, object>, IEncoderDescriptor <object>, IEncoderDescriptor <object> > >((d, n, a, p) => d.HasField(n, a, p)) .SetGenericArguments(type) .Invoke(descriptor, name, getter, recurse); return(true); } var fieldDescriptor = MethodResolver .Create <Func <IEncoderDescriptor <TEntity>, string, Func <TEntity, object>, IEncoderDescriptor <object> > >( (d, n, a) => d.HasField(n, a)) .SetGenericArguments(type) .Invoke(descriptor, name, getter); var result = MethodResolver .Create <Func <IEncoderDescriptor <object>, BindingFlags, Dictionary <Type, object>, bool> >((d, f, p) => Linker.LinkEncoder(d, f, p)) .SetGenericArguments(type) .Invoke(null, fieldDescriptor, bindings, parents); return(result is bool success && success); }
private static bool LinkDecoderAsArray <TEntity>(IDecoderDescriptor <TEntity> descriptor, BindingFlags bindings, Type type, object setter, IDictionary <Type, object> parents) { var constructor = MethodResolver .Create <Func <object> >(() => ConstructorGenerator.CreateConstructor <object>()) .SetGenericArguments(type) .Invoke(null); if (parents.TryGetValue(type, out var recurse)) { MethodResolver .Create <Func <IDecoderDescriptor <TEntity>, Func <object>, Setter <TEntity, IEnumerable <object> >, IDecoderDescriptor <object>, IDecoderDescriptor <object> > >((d, c, s, p) => d.HasElements(c, s, p)) .SetGenericArguments(type) .Invoke(descriptor, constructor, setter, recurse); return(true); } var itemDescriptor = MethodResolver .Create <Func <IDecoderDescriptor <TEntity>, Func <object>, Setter <TEntity, IEnumerable <object> >, IDecoderDescriptor <object> > >((d, c, s) => d.HasElements(c, s)) .SetGenericArguments(type) .Invoke(descriptor, constructor, setter); var result = MethodResolver .Create <Func <IDecoderDescriptor <object>, BindingFlags, Dictionary <Type, object>, bool> >((d, f, p) => Linker.LinkDecoder(d, f, p)) .SetGenericArguments(type) .Invoke(null, itemDescriptor, bindings, parents); return(result is bool success && success); }
/// <summary> /// Create setter from any <see cref="IEnumerable{T}"/> elements to array target. /// </summary> /// <typeparam name="TElement">Element type</typeparam> /// <returns>Setter callback</returns> public static Setter <TElement[], IEnumerable <TElement> > CreateFromEnumerable <TElement>() { var arrayConverter = MethodResolver.Create <Func <IEnumerable <TElement>, TElement[]> >(e => e.ToArray()); var parameterTypes = new[] { typeof(TElement[]).MakeByRefType(), typeof(IEnumerable <TElement>) }; var method = new DynamicMethod(string.Empty, null, parameterTypes, typeof(TElement).Module, true); var generator = method.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Call, arrayConverter.Method); generator.Emit(OpCodes.Stind_Ref); generator.Emit(OpCodes.Ret); return((Setter <TElement[], IEnumerable <TElement> >)method.CreateDelegate( typeof(Setter <TElement[], IEnumerable <TElement> >))); }
private static bool LinkDecoder <T>(IDecoderDescriptor <T> descriptor, BindingFlags bindings, IDictionary <Type, object> parents) { var entityType = typeof(T); parents[entityType] = descriptor; if (Linker.TryLinkDecoderAsValue(descriptor)) { return(true); } // Bind descriptor as an array of target type is also array if (entityType.IsArray) { var element = entityType.GetElementType(); var setter = MethodResolver .Create <Func <Setter <object[], IEnumerable <object> > > >(() => SetterGenerator.CreateFromEnumerable <object>()) .SetGenericArguments(element) .Invoke(null); return(Linker.LinkDecoderAsArray(descriptor, bindings, element, setter, parents)); } // Try to bind descriptor as an array if target type IEnumerable<> foreach (var interfaceType in entityType.GetInterfaces()) { // Make sure that interface is IEnumerable<T> and store typeof(T) if (!TypeResolver.Create(interfaceType) .HasSameDefinitionThan <IEnumerable <object> >(out var interfaceTypeArguments)) { continue; } var elementType = interfaceTypeArguments[0]; // Search constructor compatible with IEnumerable<> foreach (var constructor in entityType.GetConstructors()) { var parameters = constructor.GetParameters(); if (parameters.Length != 1) { continue; } var parameterType = parameters[0].ParameterType; if (!TypeResolver.Create(parameterType) .HasSameDefinitionThan <IEnumerable <object> >(out var parameterArguments) || parameterArguments[0] != elementType) { continue; } var setter = MethodResolver .Create <Func <ConstructorInfo, Setter <object, object> > >(c => SetterGenerator.CreateFromConstructor <object, object>(c)) .SetGenericArguments(entityType, parameterType) .Invoke(null, constructor); return(Linker.LinkDecoderAsArray(descriptor, bindings, elementType, setter, parents)); } } // Bind readable and writable instance properties foreach (var property in entityType.GetProperties(bindings)) { if (property.GetGetMethod() == null || property.GetSetMethod() == null || property.Attributes.HasFlag(PropertyAttributes.SpecialName)) { continue; } var setter = MethodResolver .Create <Func <PropertyInfo, Setter <object, object> > >(p => SetterGenerator.CreateFromProperty <object, object>(p)) .SetGenericArguments(entityType, property.PropertyType) .Invoke(null, property); if (!Linker.LinkDecoderAsObject(descriptor, bindings, property.PropertyType, property.Name, setter, parents)) { return(false); } } // Bind public instance fields foreach (var field in entityType.GetFields(bindings)) { if (field.Attributes.HasFlag(FieldAttributes.SpecialName)) { continue; } var setter = MethodResolver .Create <Func <FieldInfo, Setter <object, object> > >(f => SetterGenerator.CreateFromField <object, object>(f)) .SetGenericArguments(entityType, field.FieldType) .Invoke(null, field); if (!Linker.LinkDecoderAsObject(descriptor, bindings, field.FieldType, field.Name, setter, parents)) { return(false); } } return(true); }