Can I serialize Anonymous Types as xml?

后端 未结 7 2061
误落风尘
误落风尘 2020-11-27 04:48

I understood that anonymous types are marked private by the compiler and the properties are read-only. Is there a way to serialize them to xml (without deserialize) ? It wor

7条回答
  •  伪装坚强ぢ
    2020-11-27 05:33

    My first post to contribute to a website that always always helps a lot Bellow is a full solution that can be used with .net core (tested using 3.1) just call ConvertAnonymousToType.Convert("MyNewType", target, out Type newType) The return will be an object that you can use to return inside a controller or to serialize manually (System.Xml.Serialization.XmlSerializer). Using the object as a return Inside a controller: 1. configure the service (Startup.cs > ConfigureServices > services.AddMvcCore(options => options.OutputFormatters.Add(new XmlSerializerOutputFormatter());),
    2. Target Action: use [FormatFilter] and [Route(".......{format}")], 3. Return the object

    If any extra anonymous type needs to compose the reply (Metadata, Resultset, etc) DynamicTypeBuilder.CreateNewObject can be used to do service :)

    Thanks again

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Reflection.Emit;
    
    
    namespace Configuration
    {
    public static class DynamicTypeBuilder
    {
        public static object CreateNewObject(string typeName, Dictionary properties, out Type newType)
        {
            newType = CompileResultType(typeName, properties);
            return Activator.CreateInstance(newType);
        }
    
        public static Type CompileResultType(string typeName, Dictionary properties)
        {
            TypeBuilder tb = GetTypeBuilder(typeName);
            ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
    
            //Add properties
            properties.ToList().ForEach(p => CreateProperty(tb, p.Key, p.Value));
    
            //Created Type with properties
            Type objectType = tb.CreateType();
            return objectType;
        }
    
        //Create Type with an standard configuration
        private static TypeBuilder GetTypeBuilder(string typeName)
        {
            string assemblyName = typeName + "InternalAssembly";
            var an = new AssemblyName(assemblyName);
            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
            TypeBuilder tb = moduleBuilder.DefineType(typeName,
                    TypeAttributes.Public |
                    TypeAttributes.Class |
                    TypeAttributes.AutoClass |
                    TypeAttributes.AnsiClass |
                    TypeAttributes.BeforeFieldInit |
                    TypeAttributes.AutoLayout,
                    null);
            return tb;
        }
    
        private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
        {
            FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
    
            PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
            MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
            ILGenerator getIl = getPropMthdBldr.GetILGenerator();
    
            getIl.Emit(OpCodes.Ldarg_0);
            getIl.Emit(OpCodes.Ldfld, fieldBuilder);
            getIl.Emit(OpCodes.Ret);
    
            MethodBuilder setPropMthdBldr =
                tb.DefineMethod("set_" + propertyName,
                  MethodAttributes.Public |
                  MethodAttributes.SpecialName |
                  MethodAttributes.HideBySig,
                  null, new[] { propertyType });
    
            ILGenerator setIl = setPropMthdBldr.GetILGenerator();
            Label modifyProperty = setIl.DefineLabel();
            Label exitSet = setIl.DefineLabel();
    
            setIl.MarkLabel(modifyProperty);
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Stfld, fieldBuilder);
    
            setIl.Emit(OpCodes.Nop);
            setIl.MarkLabel(exitSet);
            setIl.Emit(OpCodes.Ret);
    
            propertyBuilder.SetGetMethod(getPropMthdBldr);
            propertyBuilder.SetSetMethod(setPropMthdBldr);
        }
    }
    
    public static class ConvertAnonymousToType
    {
        public static object Convert(string typeName, object target, out Type newType)
        {
            var properties = GetProperties(target);
            newType = DynamicTypeBuilder.CompileResultType(typeName, properties);
            return Convert(newType, target);
        }
    
        public static object Convert(Type type, object target)
        {
            if (target.GetType().Name == typeof(List<>).Name)
            {
                var newListType = typeof(List<>).MakeGenericType(type);
                var newList = Activator.CreateInstance(newListType);
                MethodInfo addMethod = newList.GetType().GetMethod("Add");
                ((IList)target).ToList().ForEach(e =>
                {
                    addMethod.Invoke(newList, new object[] { ConvertObject(type, e) });
                });
                return newList;
            }
            else
            {
                return ConvertObject(type, target);
            }
        }
    
        private static object ConvertObject(Type type, object refObject)
        {
            Dictionary properties = new Dictionary();
            object newObject = Activator.CreateInstance(type);
            var propertiesOrg = refObject.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
            var propertiesDes = newObject.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
            propertiesOrg.ForEach(po => propertiesDes.First(pd => pd.Name == po.Name).SetValue(newObject, po.GetValue(refObject)));
            return newObject;
        }
    
        private static Dictionary GetProperties(object target)
        {
            object objectRef = target;
            if (target.GetType().Name == typeof(List<>).Name) objectRef = ((List)target).ToList()[0];
    
            Dictionary properties = new Dictionary();
            var lstProperties = objectRef.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
            lstProperties.ForEach(p => properties.Add(p.Name, p.PropertyType));
            return properties;
        }
    
    }
    }
    
        

    提交回复
    热议问题