public static Mapper <MetaValue> .ToRule ObjectsAreDecomposed(Mapper <MetaValue> binder) { object FromMeta(MetaValue target) { return(target.Value.Match <object>( metaObject => throw new NotImplementedException(), metaValue => metaValue.Value.Value, metaArray => throw new NotImplementedException() )); } MetaObject ToMetaObject(object target) { MetaType ToMetaType(Type type) { if (type == typeof(object)) { throw new Exception(); } return(new MetaType { Name = type.GetTypeInfo().IsGenericType&& !type.IsConstructedGenericType ? null : MetaName.From(type.FullName), GenericType = type.GetTypeInfo().IsGenericType&& !type.IsConstructedGenericType ? ToMetaType(type.GetGenericTypeDefinition()) : null, GenericArguments = type.GetTypeInfo().IsGenericType&& !type.IsConstructedGenericType ? type.GetTypeInfo().GenericTypeArguments.Select(ToMetaType).ToArray() : null }); } MetaParameter ToParam(ParameterInfo arg) => new MetaParameter() { Name = MetaName.From(arg.Name), Type = ToMetaType(arg.ParameterType) }; MetaResult ToResult(Func <object> execute) { try { var result = execute(); return(MetaResult.From(binder.Map(result).AsT0)); } catch (Exception ex) { return(MetaResult.From(MetaError.From(ex.Message))); } } MetaAction ToAction(MethodInfo method) => new MetaAction() { Name = MetaName.From(method.Name), Call = args => ToResult(() => method.Invoke(target, args.Select(arg => FromMeta(arg.Value)).ToArray())), Parameters = method.GetParameters().Select(ToParam) }; MetaProperty ToProperty(PropertyInfo propertyInfo) => new MetaProperty() { Name = MetaName.From(propertyInfo.Name), Type = ToMetaType(propertyInfo.PropertyType), GetValue = !propertyInfo.CanRead ? null as Func <MetaValue> : () => { var value = propertyInfo.GetValue(target); return(value == null?MetaScalar.From(new MetaNull()) : binder.Map(value).AsT0); }, SetValue = !propertyInfo.CanWrite ? null as Action <MetaValue> : (arg) => { propertyInfo.SetValue(target, FromMeta(arg.Value)); }, }; return(new MetaObject() { Type = ToMetaType(target.GetType()), Properties = target.GetType().GetTypeInfo().DeclaredProperties.Where(t => !t.IsSpecialName && t.DeclaringType == target.GetType()).Select(ToProperty).ToArray(), Actions = target.GetType().GetTypeInfo().DeclaredMethods.Where(t => !t.Name.StartsWith("<") && !t.Name.StartsWith("get_") && !t.Name.StartsWith("set_") && t.DeclaringType == target.GetType()).Select(ToAction).ToArray() }); } return(target => (Mapper <MetaValue> .RuleOutput)(MetaValue) ToMetaObject(target)); }