public static MethodInfo BuildDynamicDtoConvertionMethod <T>(DynamicDtoInfo info)
        {
            var        key        = GetCashedMethodInfosKey(MethodBase.GetCurrentMethod(), typeof(T), info);
            MethodInfo methodInfo = null;

            if (cashedMethodInfos.ContainsKey(key))
            {
                methodInfo = cashedMethodInfos[key];
            }
            else
            {
                var methodName = "BuildDynamicDto";
                var innerCode  = GenerateDynamicDtoConvertionCode(info, "", "input");
                var type       = typeof(T);
                var methodCode =
                    $@"public static System.Dynamic.ExpandoObject {methodName}({TypeName(type)} input)
{{
    if (input == null) return null;
    {innerCode}
    return _root;
}}";
                var code           = WrapCodeIntoDummyAssembly(methodCode);
                var dummyAssembly  = BuildAssembly(code, withCSharp: true);
                var matchClassType = dummyAssembly.GetType("DummyAssembly.DummyClass");
                methodInfo = matchClassType.GetMethods().FirstOrDefault(m => m.Name == methodName);
                cashedMethodInfos.TryAdd(key, methodInfo);
            }
            return(methodInfo);
        }
        private static string GenerateDynamicDtoConvertionCode(DynamicDtoInfo dto, string varPath, string objectPath)
        {
            var varName = $"{varPath}_{dto.Name}";
            var code    = $"dynamic {varName} = new System.Dynamic.ExpandoObject();";

            if (dto.Props == null)
            {
                return(code);
            }
            foreach (var prop in dto.Props.Where(p => p.IsPrimitive))
            {
                code += $"{varName}.{prop.Name} = {objectPath} == null ? null : {objectPath}.{prop.Name};";
            }
            foreach (var prop in dto.Props.Where(p => p.IsComplex && !p.IsCollection))
            {
                var targetPath = $"{objectPath}.{prop.Name}";
                code += $@"
if ({targetPath} != null) 
{{   
    {GenerateDynamicDtoConvertionCode(prop, varName, targetPath)}
    {varName}.{prop.Name} = {varName}_{prop.Name};   
}}";
            }
            foreach (var prop in dto.Props.Where(p => p.IsCollection))
            {
                var collectionPath = $"{objectPath}.{prop.Name}";
                var itemName       = $"{varName}_{prop.Name}_Item";
                var tempCollection = $"{varName}_{prop.Name}_Temp";
                code += $@"
var {tempCollection} = new List<System.Dynamic.ExpandoObject>();
if ({collectionPath} != null) 
{{
    foreach (var {itemName} in {collectionPath}) 
    {{
        {GenerateDynamicDtoConvertionCode(prop, varName, itemName)}
        {tempCollection}.Add({varName}_{prop.Name});
    }}    
}}
{varName}.{prop.Name} = {tempCollection};";
            }
            return(code);
        }
        public DynamicDtoInfo CreateProperty(string name)
        {
            if (Props == null)
            {
                Props = new List <DynamicDtoInfo>();
            }
            else
            {
                var existing = FindPropByName(name);
                if (existing != null)
                {
                    return(existing);
                }
            }
            var isCollection = name.Contains("[]");
            var fixedName    = name.Replace("[]", "");
            var newProp      = new DynamicDtoInfo {
                Name = fixedName, IsCollection = isCollection
            };

            Props.Add(newProp);
            return(newProp);
        }
 public static DynamicDtoInfo CreateFromPropsArray(string[] propsArray, string rootName = "root")
 {
     try
     {
         var root = new DynamicDtoInfo
         {
             Name = rootName
         };
         if (propsArray == null || !propsArray.Any())
         {
             return(root);
         }
         foreach (var entry in propsArray.OrderBy(x => x.Count(c => c == '.')))
         {
             var parts = entry.Split('.');
             var owner = root;
             foreach (var part in parts)
             {
                 var existing = owner.FindPropByName(part);
                 if (existing == null)
                 {
                     owner = owner.CreateProperty(part);
                 }
                 else
                 {
                     owner = existing;
                 }
             }
         }
         return(root);
     }
     catch (Exception e)
     {
         log4net.LogManager.GetLogger(typeof(DynamicDtoInfo)).Error("Error creating Dynamic DTO structure", e);
         throw;
     }
 }