• 【.net 深呼吸】设置序列化中的最大数据量


    欢迎收看本期的《老周吹牛》节目,由于剧组严重缺钱,故本节目无视频无声音。好,先看下面一个类声明。

        [DataContract]
        public class DemoObject
        {
            [DataMember]
            public double Part1 { get; set; }
            [DataMember]
            public int Part2 { get; set; }
            [DataMember]
            public byte Part3 { get; set; }
            [DataMember]
            public string Part4 { get; set; }
        }

    这个类是老周随便瞎写的,没有特别内涵,只是用来做做实验而已。注意类型上应用的attribute,它被定义为数据协定。

    下面是重点,对这个类的实例进行序列化,所以,我们先得new一个实例。

                DemoObject obj = new DemoObject
                {
                    Part1 = 33.0065d,
                    Part2 = 995,
                    Part3 = 120,
                    Part4 = "kill dog"
                };

    然后,可以序列化了。

                DataContractSerializerSettings settings = new DataContractSerializerSettings
                {
                    MaxItemsInObjectGraph = 3

    }; DataContractSerializer szr = new DataContractSerializer(obj.GetType(), settings); szr.WriteObject(stream, obj);

    注意,在序列化前,我创建了一个DataContractSerializerSettings对象,并把一个名为 MaxItemsInObjectGraph 的属性设置为3,这是啥含义呢,别急,咱们看看这段代码在运行时会发生什么意外。

    从上面的高清图中大家看到了,它说 MaxItemsInObjectGraph = 3,这尺码太小了,穿不上。

    MaxItemsInObjectGraph 值用来设置实例对象在序列化的时候,能够处理数据项的最大值

    那么,DemoObject 类在序列化时,到底会有多少个数据项呢,怎么计算的呢。

    来,我们一层一层地剥皮。

    第一层:DemoObject对象本身,算1个。

    第二层:它有四个属性,而且每个属性的类型都是基础类型(string、int等),基础类型都视为单个数据项,所以此层有4项数据。

    好,两层加起来就是 = 5,也就是说,要序列化 DemoObject 类对象,序列化程序需要处理5个数据项,因此,3太小了,咱们换个大号的,把它改为5。

                DataContractSerializerSettings settings = new DataContractSerializerSettings
                {
                    MaxItemsInObjectGraph = 5
                };

    这么一改,就可以正常序列化了。

    如果还不过瘾,咱们继续探讨。

    来,看看下面这个类。

        [DataContract]
        public class Something
        {
            [DataMember]
            public List<double> Items { get; private set; }
    
            public Something()
            {
                Items = new List<double>();
            }
        }

    你猜猜,它在序列化时要处理多少项数据?

    好,咱们设置最大值为3,试试看。

                Something obj = new Something();
                obj.Items.Add(0.001d);
                obj.Items.Add(-99.99d);
    
                DataContractSerializerSettings settings = new DataContractSerializerSettings
                {
                    MaxItemsInObjectGraph = 3
                };
    
                DataContractSerializer sz = new DataContractSerializer(obj.GetType(), settings);
                sz.WriteObject(stream, obj);

    运行上面代码,你会收到异常信息,这说明,3个数据项是不够的。

    那么,现在咱们来数一下:

    第一层,Something 类实例自身算是1个对象。

    第二层,Something类中 有个Items属性,它是一个List<T>对象,算是1个。

    第三层,list中有两个double值,算是2个对象。

    最后,序列化要处理的对象数 = 1 + 1 + 2 = 4。

    所以,把上面代码改一下,改为4,或者大于4都行,因为 MaxItemsInObjectGraph 设置的是取大项数,你设100也行。

                DataContractSerializerSettings settings = new DataContractSerializerSettings
                {
                    MaxItemsInObjectGraph = 4
                };

    这样就可以正常序列化了。序列化生成以下XML。

    <Something xmlns="……" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <Items xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <a:double>0.001</a:double>
        <a:double>-99.99</a:double>
      </Items>
    </Something>

    下面咱们来个变态级别的,你能数出来吗?

        [DataContract]
        public class Employee
        {
            [DataMember]
            public string Name { get; set; }
            [DataMember]
            public int Age { get; set; }
        }
    
        [DataContract]
        public class PartMent
        {
            [DataMember]
            public string PartName { get; set; }
            [DataMember]
            public Employee Manager { get; set; }
            [DataMember]
            public List<Employee> Members { get; set; }
        }

    注意,这两个数据协有关联,PartMent实例会引用N个Employee 实例。而且,PartMent 中有个list类型的属性,所以,序列化的数据项数量是变动的,因为list中可以添加X个对象。

    我们先把可以确定的对象数算出来,对于可变的,我们就用一个x来指代。

    1,PartMent 自身算1个。

    2,PartName 属性是字符串类型,算1个。

    3、Manager 属性是Employee类型。Employee类好计算吧,类实例本身1个,Name 和 Age 属性都是基础类型,共2个,加起来即一个Employee实例会包含 3 个数据项。

    4、Members 属性是个List<T>,list 实例自身算 1 个,而里面每个Employee实例,刚刚算过,是3个,如果有x个实例,就是 3 × x 个数据项, 合计为 1 + 3x 个数据项。

    总结上面的分析,得出一个通用公式: n = 1+1+3+(1+3x) ,再整理一下就是:n = 6 + 3x。

    好,来个代码演示。

                PartMent pmt = new PartMent();
                pmt.PartName = "人渣部门";
                pmt.Manager = new Employee { Name = "老鬼", Age = 55 };
                // 1 + 1 + (1 + 2) = 5
    
                List<Employee> emps = new List<Employee>();
                emps.Add(new Employee { Name = "小李", Age = 25 });
                emps.Add(new Employee { Name = "小刘", Age = 40 });
                emps.Add(new Employee { Name = "小杜", Age = 37 });
                pmt.Members = emps;
                // (3 * 3) + 1 = 10
    
                DataContractSerializerSettings settings = new DataContractSerializerSettings
                {
                    MaxItemsInObjectGraph = 15
                };
    
                DataContractSerializer sz = new DataContractSerializer(pmt.GetType(), settings);
                sz.WriteObject(stream, pmt);

    上面代码中,在 list 里面放了 3 个 Employee 实例,套上面得到的公式 6+3*3 = 15,所以,这个实例序列化后会处理 15 个数据项,生成的XML如下:

    <PartMent xmlns="……" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <Manager>
        <Age>55</Age>
        <Name>老鬼</Name>
      </Manager>
      <Members>
        <Employee>
          <Age>25</Age>
          <Name>小李</Name>
        </Employee>
        <Employee>
          <Age>40</Age>
          <Name>小刘</Name>
        </Employee>
        <Employee>
          <Age>37</Age>
          <Name>小杜</Name>
        </Employee>
      </Members>
      <PartName>人渣部门</PartName>
    </PartMent>

    怎么样,刺激吧。

    当然了,我只是为了演示,就设置为15个,其实,最大值一般不会这么小,设置几百个也可以。序列化选项之所以会有这个最大值的限制数值,是为了防止一些不良青年搞恶意破坏,比如,如果某个客户端要向服务器提交数据,数据内容自然是要先序列化,然后才能通过网络发送,尤其像web服务调用这种情况。你想想,如果不设置个限制值,别有用心的人,可以故意地弄一个特大对象来攻击服务器。

    OK,今天的吹牛节目就此结束了,下次有空再见。

  • 相关阅读:
    TypeError: 'encoding' is an invalid keyword argument for this function 解决Python 2.7
    valid-palindrome leetcode C++
    valid-palindrome leetcode C++
    word-break-ii leetcode C++
    word-break-ii leetcode C++
    word-break leetcoder C++
    word-break leetcoder C++
    word-ladder leetcoder C++
    word-ladder leetcoder C++
    triangle leetcode C++
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/6088755.html
Copyright © 2020-2023  润新知