Generic Interface pass by ref

CSharp · Console

/Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;

namespace RecursiveClassProperties
{
    public static class Program
    {
        static void Main(string[] args)
        {
            var order = new Order()
            {
                Id = Guid.NewGuid(),
                Customer = new Customer(Gender.Male, "John", "Smith", new List<string> { "Test" }),
                Address = "12 Some Drive",
                Postcode = "AB12 3CD",
                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("\n");
            Console.WriteLine(JsonSerializer.Serialize(formProperties, new JsonSerializerOptions { WriteIndented = true }));
            var item = CreateItem(typeof(Order), formProperties);
            Console.WriteLine("\n");
            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)
        {
            if (result is null)
            {
                result = Activator.CreateInstance(type);
                isBase = true;
            }

            try
            {
                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);
                        }
                        else
                        {
                            if (property.PropertyType.IsPrimitive || property.PropertyType == typeof(decimal) || property.PropertyType == typeof(string) || property.PropertyType.IsEnum || property.PropertyType == typeof(Guid))
                            {
                                if (property.PropertyType.IsEnum)
                                {
                                    if (isBase)
                                    {
                                        var enumValue = Enum.Parse(property.PropertyType, formProperties[property.Name].Value);
                                        type.GetProperty(property.Name).SetValue(result, enumValue);
                                    }
                                    else
                                    {
                                        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);
                                        }
                                    }
                                }
                                else
                                {
                                    if (isBase)
                                    {
                                        if (property.PropertyType == typeof(Guid)) type.GetProperty(property.Name).SetValue(result, Guid.NewGuid());
                                        else type.GetProperty(property.Name).SetValue(result, formProperties[property.Name].Value);
                                    }
                                    else
                                    {
                                        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);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch { return result; }

            return result;
        }

        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);
            if (result is null)
            {
                result = new Dictionary<string, string>();
                isBase = true;
            }
            if (@object is null && !isBase) @object = Activator.CreateInstance(activationType);
            else if (@object == null || @object.GetType().IsPrimitive) return result;

            try
            {
                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];
                                    items.CopyTo(list, 0);
                                    var joined = string.Join("||", list);
                                    AddResult(property.Name, joined, isBase);
                                }
                                else GetAllProperties(item, result);
                            }
                        }
                        else
                        {
                            if (property.PropertyType.Assembly == type.Assembly && !property.PropertyType.IsEnum)
                            {
                                if (value is null) GetAllProperties(value, result, property.PropertyType);
                                else GetAllProperties(value, result);
                            }
                            else
                            {
                                if (value is null) AddResult(property.Name, string.Empty, isBase);
                                else
                                {
                                    var valueType = value.GetType();
                                    if (valueType.IsPrimitive || valueType == typeof(decimal) || valueType == typeof(string) || valueType.IsEnum || valueType == typeof(Guid))
                                    {
                                        if (valueType.IsEnum)
                                        {
                                            var enumValue = Enum.GetName(valueType, value);
                                            AddResult(property.Name, enumValue.ToString(), isBase);
                                        }
                                        else AddResult(property.Name, value.ToString(), isBase);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch { return result; }

            return result;
        }
    }

    [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 class Order
    {
        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 class Test
    {
        public Test(string value) => Value = value;
        public string Value { get; set; }
    }
	
	public enum Gender
	{
		Male,
		Female
	}

    public class Customer
    {
        public Customer() { }
        public Customer(Gender gender, string firstName, string lastName, List<string> test)
        {
            Gender = gender;
            FirstName = firstName;
            LastName = lastName;
            Test = 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; }
    }
}
;