using System.Collections;
using System.Collections.Generic;
namespace RecursiveClassProperties
public static class Program
static void Main(string[] args)
Customer = new Customer(Gender.Male, "John", "Smith", new List<string> { "Test" }),
Address = "12 Some Drive",
Test = new List<string> { "Test1", "Test2" },
Test2 = new List<Test> { new Test("Test1"), new Test("Test2") }
var properties = GetAllProperties(order);
Console.WriteLine(JsonSerializer.Serialize(properties, new JsonSerializerOptions { WriteIndented = true }));
var formProperties = GetFormProperties(new Order());
formProperties["Customer.FirstName"].Value = "John";
formProperties["Customer.LastName"].Value = "Smith";
formProperties["Customer.Gender"].Value = "Male";
formProperties["Address"].Value = "12 Some Drive";
formProperties["Postcode"].Value = "AB12 3CD";
Console.WriteLine(JsonSerializer.Serialize(formProperties, new JsonSerializerOptions { WriteIndented = true }));
var item = CreateItem(typeof(Order), formProperties);
Console.WriteLine(JsonSerializer.Serialize(item, new JsonSerializerOptions { WriteIndented = true }));
private static object CreateItem(Type type, Dictionary<string, FormResponse> formProperties, object result = null, string parentName = null, bool isBase = false)
result = Activator.CreateInstance(type);
var properties = type.GetProperties();
foreach (var property in properties)
if (!Attribute.IsDefined(property, typeof(FormIgnoreAttribute)) && property.GetSetMethod() is not null)
if (property.PropertyType.Assembly == type.Assembly && !property.PropertyType.IsEnum)
var value = Activator.CreateInstance(property.PropertyType);
type.GetProperty(property.Name).SetValue(result, value);
CreateItem(property.PropertyType, formProperties, result);
if (property.PropertyType.IsPrimitive || property.PropertyType == typeof(decimal) || property.PropertyType == typeof(string) || property.PropertyType.IsEnum || property.PropertyType == typeof(Guid))
if (property.PropertyType.IsEnum)
var enumValue = Enum.Parse(property.PropertyType, formProperties[property.Name].Value);
type.GetProperty(property.Name).SetValue(result, enumValue);
var filteredProperties = formProperties.Where(formProperty => type.Name == formProperty.Key.Split('.')[..^1].FirstOrDefault() && property.Name == formProperty.Key.Split('.').Last());
if (filteredProperties.Any())
var itemProperties = filteredProperties.FirstOrDefault();
var enumValue = Enum.Parse(property.PropertyType, itemProperties.Value.Value);
var item = result.GetType().GetProperty(type.Name).GetValue(result);
type.GetProperty(property.Name).SetValue(item, enumValue);
if (property.PropertyType == typeof(Guid)) type.GetProperty(property.Name).SetValue(result, Guid.NewGuid());
else type.GetProperty(property.Name).SetValue(result, formProperties[property.Name].Value);
var filteredProperties = formProperties.Where(formProperty => type.Name == formProperty.Key.Split('.')[..^1].FirstOrDefault() && property.Name == formProperty.Key.Split('.').Last());
if (filteredProperties.Any())
var itemProperties = filteredProperties.FirstOrDefault();
var item = result.GetType().GetProperty(type.Name).GetValue(result);
type.GetProperty(property.Name).SetValue(item, itemProperties.Value.Value);
private static Dictionary<string, FormResponse> GetFormProperties(object @object) => GetAllProperties(@object).ToDictionary(x => x.Key, x => new FormResponse(string.Empty));
private static Dictionary<string, string> GetAllProperties(object @object, Dictionary<string, string> result = null, Type activationType = null)
void AddResult(string property, string value, bool isBase)
if (isBase) result.Add(property, value);
else result.Add($"{@object.GetType().Name}.{property}", value);
var isBase = default(bool);
result = new Dictionary<string, string>();
if (@object is null && !isBase) @object = Activator.CreateInstance(activationType);
else if (@object == null || @object.GetType().IsPrimitive) return result;
var type = @object.GetType();
var properties = type.GetProperties();
foreach (var property in properties)
Console.WriteLine(property.Name);
if (!Attribute.IsDefined(property, typeof(FormIgnoreAttribute)))
var value = property.GetValue(@object, null);
if (value is IList items)
foreach (var item in items)
var itemType = item.GetType();
if (itemType.IsPrimitive || itemType == typeof(decimal) || itemType == typeof(string) || itemType.IsEnum || itemType == typeof(Guid))
var list = new string[items.Count];
var joined = string.Join("||", list);
AddResult(property.Name, joined, isBase);
else GetAllProperties(item, result);
if (property.PropertyType.Assembly == type.Assembly && !property.PropertyType.IsEnum)
if (value is null) GetAllProperties(value, result, property.PropertyType);
else GetAllProperties(value, result);
if (value is null) AddResult(property.Name, string.Empty, isBase);
var valueType = value.GetType();
if (valueType.IsPrimitive || valueType == typeof(decimal) || valueType == typeof(string) || valueType.IsEnum || valueType == typeof(Guid))
var enumValue = Enum.GetName(valueType, value);
AddResult(property.Name, enumValue.ToString(), isBase);
else AddResult(property.Name, value.ToString(), isBase);
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public class FormIgnoreAttribute : Attribute { }
public class FormResponse
public FormResponse(string value) => Value = value;
public string Value { get; set; }
public Guid Id { get; set; }
public Customer Customer { get; set; }
public string Address { get; set; }
public string Postcode { get; set; }
public List<string> Test { get; set; }
public List<Test> Test2 { get; set; }
public Test(string value) => Value = value;
public string Value { get; set; }
public Customer(Gender gender, string firstName, string lastName, List<string> test)
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName => $"{FirstName} {LastName}";
public Gender Gender { get; set; }
public List<string> Test { get; set; }