using Newtonsoft.Json.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace RecursiveClassProperties
public static class Program
static void Main(string[] args)
var properties = GetItemProperties(CreateDefaultItem(typeof(Order)));
var formProperties = GetFormItemProperties(properties);
formProperties["Id"].Value = id.ToString();
formProperties["Customer.FirstName"].Value = "Scott";
formProperties["Customer.LastName"].Value = "Kane";
formProperties["Customer.Age"].Value = "26";
var propertyType = typeof(Order).GetProperty("Genders").PropertyType.GetGenericArguments().FirstOrDefault();
formProperties.Add("Genders[0]", new FormResponse(((int)Gender.Male).ToString(), propertyType));
formProperties.Add("Genders[1]", new FormResponse(((int)Gender.Female).ToString(), propertyType));
formProperties.Add("Genders[2]", new FormResponse(((int)Gender.Male).ToString(), propertyType));
formProperties.Remove("Genders");
var item = (Order)CreateFormItem(typeof(Order), formProperties);
Console.WriteLine($"Item:\n{JsonSerializer.Serialize(item, new JsonSerializerOptions { WriteIndented = true })}");
var order = (Order)CreateDefaultItem(typeof(Order));
order.Customer.FirstName = "Scott";
order.Customer.LastName = "Kane";
order.Genders = new List<Gender> { Gender.Male, Gender.Female, Gender.Male };
var orderProperties = GetItemProperties(order);
var orderFormProperties = GetFormItemProperties(orderProperties);
var orderItem = (Order)CreateFormItem(typeof(Order), orderFormProperties);
Console.WriteLine($"OrderItem:\n{JsonSerializer.Serialize(orderItem, new JsonSerializerOptions { WriteIndented = true })}");
Console.WriteLine($"Equal(Item, OrderItem): {item.IsDeepEqual(orderItem)}");
var property = GetPropertyFromKey("Customer.FirstName", item);
var property1 = GetPropertyFromKey("Customer.Test.String", item);
var property2 = GetPropertyFromKey("Genders", item);
var value = GetPropertyValueFromKey("Customer.FirstName", item);
SetPropertyValueFromKey("Customer.FirstName", item, "NewName");
var value1 = GetPropertyValueFromKey("Customer.FirstName", item);
var value2 = GetPropertyValueFromKey("Customer.Test.String", item);
var value3 = GetPropertyValueFromKey("Genders", item);
public static object SetPropertyValueFromKey(string key, object item, object value, string[] properties = null)
var propertyNames = properties is null ? key.Split('.').ToList() : properties.ToList();
var type = item.GetType();
if (propertyNames.Count == 1)
type.GetProperty(propertyNames.FirstOrDefault()).SetValue(item, value);
var names = key.Split('.')[1..];
item = type.GetProperty(propertyNames.FirstOrDefault()).GetValue(item);
return SetPropertyValueFromKey(string.Join('.', names), item, value, names);
public static object GetPropertyValueFromKey(string key, object item, string[] properties = null)
var propertyNames = properties is null ? key.Split('.').ToList() : properties.ToList();
var type = item.GetType();
if (propertyNames.Count == 1) return type.GetProperty(propertyNames.FirstOrDefault()).GetValue(item);
var names = key.Split('.')[1..];
item = type.GetProperty(propertyNames.FirstOrDefault()).GetValue(item);
return GetPropertyValueFromKey(string.Join('.', names), item, names);
public static PropertyInfo GetPropertyFromKey(string key, object item, string[] properties = null)
var propertyNames = properties is null ? key.Split('.').ToList() : properties.ToList();
var type = item.GetType();
if (propertyNames.Count == 1) return type.GetProperty(propertyNames.FirstOrDefault());
var names = key.Split('.')[1..];
item = type.GetProperty(propertyNames.FirstOrDefault()).GetValue(item);
return GetPropertyFromKey(string.Join('.', names), item, names);
private static Dictionary<string, FormResponse> GetFormItemProperties(Dictionary<string, object> properties) => properties.ToDictionary(x => x.Key, x => x.Value is string ? new FormResponse(x.Value.ToString(), x.Value.GetType()) : new FormResponse(JsonSerializer.Serialize(x.Value), x.Value.GetType()));
private static Dictionary<string, object> GetItemProperties(object item) => (Dictionary<string, object>)JObject.Parse(JsonSerializer.Serialize(item)).Flatten();
private static TItem CreateFormItem<TItem>(Dictionary<string, FormResponse> formProperties) => (TItem)CreateFormItem(typeof(TItem), formProperties);
private static TItem CreateDefaultItem<TItem>() => (TItem)CreateDefaultItem(typeof(TItem));
private static object CreateFormItem(Type type, Dictionary<string, FormResponse> formProperties, object result = null)
static object FormResponseToObject(string value, Type type)
if (type == typeof(string)) return value;
if (type.Name.Contains("EmptyPartition")) type = typeof(List<object>);
return JsonSerializer.Deserialize(value, type);
var properties = formProperties.ToDictionary(x => x.Key, x => FormResponseToObject(x.Value.Value, x.Value.Type));
return JsonSerializer.Deserialize<Order>(properties.Unflatten().ToString());
private static object CreateDefaultItem(Type type, object item = null)
void SetProperty(PropertyInfo property, object instance)
if (property.PropertyType.IsPrimitive || property.PropertyType.IsEnum || property.PropertyType == typeof(string))
if (!type.IsAssignableTo(typeof(IList)) && !type.IsInterface)
if (property.PropertyType.IsPrimitive) property.SetValue(instance, Activator.CreateInstance(property.PropertyType));
if (property.PropertyType == typeof(string)) property.SetValue(instance, string.Empty);
property.SetValue(item, Activator.CreateInstance(property.PropertyType));
CreateDefaultItem(property.PropertyType, property.GetValue(item));
if (item is null) item = Activator.CreateInstance(type);
foreach (var property in type.GetProperties())
if (property.GetSetMethod() is not null)
SetProperty(property, item);
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public class FormIgnoreAttribute : Attribute { }
public class FormResponse
public FormResponse(string value, Type type, Type listType = null)
public string Value { get; set; }
public Type Type { get; set; }
public Guid Id { get; set; }
public Customer Customer { get; set; }
public string Address { get; set; }
public string Postcode { get; set; }
public int Age { get; set; }
public Test Test { get; set; }
public List<Gender> Genders { get; set; }
public List<string> Tests { get; set; }
public string String { get; set; }
public int Number { get; set; }
public List<Gender> Genders { get; set; }
public List<string> Strings { get; set; }
public List<int> Numbers { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName => $"{FirstName} {LastName}";
public int Age { get; set; }
public Gender Gender { get; set; }
public Test Test { get; set; }
public List<Gender> Genders { get; set; }
public List<string> Strings { get; set; }
public List<int> Numbers { get; set; }