利用XMLSerializer将对象串行化到XML

本文中的思路、二元hashtable等,大力感谢Leo Chen的帮助!
对于XmlSerializer带来的内存占用过高,最终导致Out Of Memory的问题,参见以前这个链接:http://www.cnblogs.com/juqiang/archive/2008/01/15/1039936.html
(但是那篇文章中对于XmlSerializer构造方法的说明,是错误的。那段代码没有问题,有问题的是下面的)

首先看System.Xml.Serialization.XmlSerializer的构造方法,一共分为三大类:

public XmlSerializer(Type type) : this(type, (string) null)
public XmlSerializer(Type type, string defaultNamespace)
这两个方法,采用了上文引用的那篇文章的处理方式,应用了cache,这是正确的,不会造成内存占用过高。(上文引用那篇文章里面这个地方解释错了)

另一大类的方法是:
public XmlSerializer(XmlTypeMapping xmlTypeMapping),这个方法里面会产生一个tempAssembly,但是没有用缓存方式来处理。

有问题的一类方法是:
public XmlSerializer(Type type, Type[] extraTypes) : this(type, null, extraTypes, null, null, null, null)
public XmlSerializer(Type type, XmlAttributeOverrides overrides) : this(type, overrides, new Type[0], null, null, null, null)
public XmlSerializer(Type type, XmlRootAttribute root) : this(type, null, new Type[0], root, null, null, null)
public XmlSerializer(Type type, XmlAttributeOverrides overrides, Type[] extraTypes, XmlRootAttribute root, string defaultNamespace) : this(type, overrides, extraTypes, root, defaultNamespace, null, null)
public XmlSerializer(Type type, XmlAttributeOverrides overrides, Type[] extraTypes, XmlRootAttribute root, string defaultNamespace, string location, Evidence evidence)

前4个都最终调用了最后一个构造方法,里面产生了一个tempAssembly,也没有用缓存方式来护理。

我上次提到的那个问题,问题代码如下:
public static TReturn Convert< TReturn, TInput>(TInput input) where TReturn: class, new() where TInput: IProvisioningObject
{
    using (MemoryStream stream = new MemoryStream())
    {
        new XmlSerializer(typeof(TInput)).Serialize((Stream) stream, input);
        stream.Position = 0L;
        XmlSerializer serializer = new XmlSerializer(typeof(TReturn), new XmlRootAttribute(input.GetType().Name));
        return (TReturn) serializer.Deserialize(stream);
    }
}
注意红色的代码,这里产生了一个tempAssembly,没有做缓存。这里的核心问题在于,tempAssembly不会被自动释放掉,除非appdomain被unload。
修正的方式类似于XmlSerializer的处理方式,采用一个二元Hashtable来做。代码修改如下:
 1   private   static  TempXmlSerializerCache cache  =   new  TempXmlSerializerCache();
 2
 3          public   static  TReturn Convert < TReturn, TInput > (TInput input)
 4              where  TReturn :  class new ()
 5              where  TInput : IProvisioningObject
 6          {
 7            using (MemoryStream stream = new MemoryStream())
 8            {
 9                new XmlSerializer(typeof(TInput)).Serialize((Stream)stream, input);
10                stream.Position = 0L;
11
12                XmlSerializer serializer = cache[typeof(TReturn).ToString(), input.GetType().Name];
13                if (serializer == null)
14                {
15                    lock (cache)
16                    {
17                        serializer = cache[typeof(TReturn).ToString(), input.GetType().Name];
18                        if (serializer == null)
19                        {
20                            serializer = new XmlSerializer(typeof(TReturn), new XmlRootAttribute(input.GetType().Name));
21                            cache.Add(typeof(TReturn).ToString(), input.GetType().Name, serializer);
22                        }

23                    }

24                }

25                return (TReturn)serializer.Deserialize(stream);
26            }

27        }

这里的二元Hashtable,是从XmlSerializer里面扒出来的,稍微修改了一下而已:

     public   class  TempXmlSerializerCache
    
{
        
private Hashtable cache = new Hashtable();

        
public void Add(string ns, object o, XmlSerializer serializer)
        
{
            XmlSerializerCacheKey key 
= new XmlSerializerCacheKey(ns, o);
            
lock (this)
            
{
                
if (this.cache[key] != serializer)
                
{
                    Hashtable hashtable 
= new Hashtable();
                    
foreach (object obj2 in this.cache.Keys)
                    
{
                        hashtable.Add(obj2, 
this.cache[obj2]);
                    }

                    
this.cache = hashtable;
                    
this.cache[key] = serializer;
                }

            }

        }


        
public XmlSerializer this[string ns, object o]
        
{
            
get
            
{
                
return (XmlSerializer)this.cache[new XmlSerializerCacheKey(ns, o)];
            }

        }

    }


以及:
    public   class  XmlSerializerCacheKey
    
{
        
private string ns;
        
private object type;

        
public XmlSerializerCacheKey(string ns, object type)
        
{
            
this.type = type;
            
this.ns = ns;
        }


        
public override bool Equals(object o)
        
{
            XmlSerializerCacheKey key 
= o as XmlSerializerCacheKey;
            
if (key == null)
            
{
                
return false;
            }

            
return ((key.type == this.type) && (key.ns == this.ns));
        }


        
public override int GetHashCode()
        
{
            
return (((this.ns != null? this.ns.GetHashCode() : 0^ ((this.type != null? this.type.GetHashCode() : 0));
        }

    }

结束.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值