ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

关于Xml序列化中使用抽象类导致无法正确序列化而且修改方法过于讨厌这件事

2021-12-12 18:04:24  阅读:114  来源: 互联网

标签:Xml body string static typeof var 抽象类 序列化 Expression


在Xml序列化的时候,存在抽象类属性,由于无法确定具体的类型,导致使用XmlSerializer的时候报错

参考网上的修改方法

  1. 使用XmlInclude标签

然而在使用的过程中,发现对多个类型标注时,也会报错

abstract class BaseData{}

class DataType1 : BaseData
{
    public string prop1 {get;set;}
    public string prop2 {get;set;}
}

class DataType2 : BaseData
{
    public string prop3 {get;set;}
    public string prop4 {get;set;}
}

class XmlData
{
    [XmlInclude(typeof(DataType1))]
    [XmlInclude(typeof(DataType2))]
    ...
    ...
    public BaseData Data {get;set;}
}

在我的项目中,几十个接口,每个接口一个Model,那不得难看死。

而且或许是因为使用方法不对,导致报错,暂时未找到解决办法。

生气,还是自己撸一个序列化吧

基本思路就是 反射+递归 创建 MakeSerializer<T>,在初始化中,使用Expression构建委托

调用方法

MakeSerializer<T>.Invoke(obj)

当然,目前也仅仅是可用的水平,主要还是巩固一下Expression动态构建相关方面的知识,而且目前在项目中使用暂时没出什么问题。

public static class MakeSerializer<T>
    {
        private static Func<T, string> func;

        public static string Invoke(T source)
        {
            return func.Invoke(source);
        }

        private static MethodInfo StringBuilderAppend = typeof(StringBuilder).GetMethod("Append", new Type[] { typeof(string) });
        private static MethodInfo StringBuilderToString = typeof(StringBuilder).GetMethod("ToString", new Type[0]);
        private static MethodInfo GetTypeMethod = typeof(object).GetMethod("GetType", new Type[0]);
        private static MethodInfo MakeGenericType = typeof(Type).GetMethod("MakeGenericType", new Type[] { typeof(Type[]) });
        private static MethodInfo GetMethod = typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string) });
        private static MethodInfo InvokeMethod = typeof(MethodBase).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) });

        static MakeSerializer()
        {
            var type = typeof(T);
            List<Expression> body = new List<Expression>();
            ParameterExpression sourceParameterExpression = Expression.Parameter(type, "source");
            // var ret = null;
            ParameterExpression varStringBuilder = Expression.Variable(typeof(StringBuilder), "ret");
            // var ret = new StringBuilder();
            BinaryExpression assignStringBuilder = Expression.Assign(varStringBuilder, Expression.New(typeof(StringBuilder)));
            body.Add(assignStringBuilder);
            // ret.Append("<?xml version="1.0" encoding="utf-8"?>");
            //MethodCallExpression appendExpression = Expression.Call(varStringBuilder, StringBuilderAppend, Expression.Constant("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
            //body.Add(appendExpression);
            var rootName = GetTypeRootName(type);
            // ret.Append("<root>")
            var rootStart = Expression.Call(varStringBuilder, StringBuilderAppend, Expression.Constant(StartFormat(rootName)));
            body.Add(rootStart);

            ScanProp(type, sourceParameterExpression, varStringBuilder, body);

            // ret.Append("</root>")
            var rootEnd = Expression.Call(varStringBuilder, StringBuilderAppend, Expression.Constant(EndFormat(rootName)));
            body.Add(rootEnd);
            MethodCallExpression toStringExpression = Expression.Call(varStringBuilder, StringBuilderToString);
            body.Add(toStringExpression);
            var block = Expression.Block(new ParameterExpression[] { varStringBuilder }, body);
            var lambdaExpression = Expression.Lambda(block, sourceParameterExpression);
            func = (Func<T, string>)lambdaExpression.Compile();
        }
        private static string GetTypeRootName(Type type)
        {
            var attrs = type.GetCustomAttributes(typeof(XmlRootAttribute), true);
            if (attrs.Length == 0)
                return type.Name;
            var root = (XmlRootAttribute)attrs[0];
            return root.ElementName;
        }
        private static void ScanProp(Type type, ParameterExpression parameter, ParameterExpression var, List<Expression> body)
        {
            var props = type.GetProperties();
            foreach (var prop in props)
            {
                if (!prop.CanWrite) continue;
                if (prop.PropertyType.IsAssignableFrom(typeof(XmlData)) || typeof(XmlData).IsAssignableFrom(prop.PropertyType))
                {
                    //ScanProp(prop.PropertyType, parameter, var, body);
                    // var type = source.XmlData.GetType()
                    var propExp = Expression.Property(parameter, prop);
                    var getTypeExp = Expression.Call(propExp, GetTypeMethod);
                    var gType = Expression.Constant(typeof(MakeSerializer<>));
                    var getTypeMethodExp = Expression.Call(gType, MakeGenericType, Expression.NewArrayInit(typeof(Type), getTypeExp));
                    // var invoke = gType.GetMethod("Invoke");
                    var getInvokeExp = Expression.Call(getTypeMethodExp, GetMethod, Expression.Constant("Invoke"));
                    // var str = invoke.Invoke(source.XmlData)
                    var resultExp = Expression.Call(getInvokeExp, InvokeMethod, Expression.Constant(null), Expression.NewArrayInit(typeof(object), propExp));
                    MethodCallExpression methodCallExpression1 = Expression.Call(var, StringBuilderAppend, Expression.Convert(resultExp, typeof(string)));
                    body.Add(methodCallExpression1);
                }
                else
                {
                    var propStart = Expression.Call(var, StringBuilderAppend, Expression.Constant(StartFormat(GetMemberName(prop))));
                    body.Add(propStart);
                    MemberExpression memberExpression = Expression.Property(parameter, prop);
                    var propValue = Expression.Call(var, StringBuilderAppend, memberExpression);
                    body.Add(propValue);
                    var propEnd = Expression.Call(var, StringBuilderAppend, Expression.Constant(EndFormat(GetMemberName(prop))));
                    body.Add(propEnd);
                }
            }
        }
        private static string StartFormat(string s)
        {
            return $"<{s}>";
        }
        private static string EndFormat(string s)
        {
            return $"</{s}>";
        }
        private static string GetMemberName(MemberInfo Member)
        {
            if (Member.GetCustomAttributes(typeof(XmlElementAttribute), true).Count() > 0)
            {
                return ((XmlElementAttribute)Member.GetCustomAttributes(typeof(XmlElementAttribute), true)[0]).ElementName;
            }
            else
            {
                return Member.Name;
            }

        }
    }

标签:Xml,body,string,static,typeof,var,抽象类,序列化,Expression
来源: https://www.cnblogs.com/marvelTitile/p/15679964.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有