在Silverlight中,已经不包含SerializableAttribute,不过没有了这个标记也不会影响序列化。去除这个特性标记的原因,是因为已经了一系列XML为开头的用于序列化的特性标记。
对于这个变动,没有什么难点,主要是比较麻烦,需要逐一删除。当然如果不想删除,最简单的方式就是,自己创建一个SerializableAttribute 。
说起来,就是不在Silverlight中,也没有办法用XmlSerializer对Dictionary<>进行序列化。而我直接实现了一个能够Xml序列化的Dictionary,代码如下:
public class XmlSerDictionary<TKey, Tvalue> : Dictionary<TKey, Tvalue>, IXmlSerializable { #region IXmlSerializable Members System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { return null; } void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) { XmlDocument doc = new XmlDocument(); doc.LoadXml(reader.ReadOuterXml()); foreach (XmlElement item in doc.ChildNodes[0].ChildNodes) { TKey key = (TKey)Convert.ChangeType(item.GetAttribute("key"), typeof(TKey)); Tvalue value = (Tvalue)Convert.ChangeType(item.InnerText, typeof(Tvalue)); this.Add(key, value); } } void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) { foreach (var item in this) { writer.WriteStartElement("item"); writer.WriteAttributeString("key", item.Key.ToString()); writer.WriteValue(item.Value); writer.WriteEndElement(); } } #endregion }
但是在ReadXml方法中,我之前使用XmlDocument,这个东西在Silverlight中已经不存在,只能用XDocument或XElement代替,新的代码如下:
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) { XElement ele = XElement.Parse(reader.ReadOuterXml()); foreach (var item in ele.Descendants()) { TKey key = (TKey)Convert.ChangeType(item.Attribute("key").Value, typeof(TKey), null); Tvalue value = (Tvalue)Convert.ChangeType(item.Value, typeof(Tvalue),null); this.Add(key, value); } }
当然,如果不是要兼容之前的Xml序列化的文件,完全可以用DataContact对Dictionary<>直接进行序列化(甚至还可以支持JSON)
注意上述修改的代码,我们发现Convert.ChangeType的参数也发生了变化,在之前Convert.ChangeType这个方法支持2个参数,而在Silverlight中只支持3个参数,所以最后要传入null。
从这个细节,可以看出微软为了缩减Silverlight的大小不予余力,精简到每个方法。
Find是LINQ出现之前就提供的扩展方法,而Silverlight再次为了缩减大小,把类似的一些扩展方法也去除了。为了不对原有代码造成太大的改动,我只好自己实现了Find方法,如下:
public static T Find<T>(this IEnumerable<T> list, Func<T, bool> comparison) { foreach (T item in list) { if (comparison(item)) { return item; } } return default(T); }
当然,也可以用First扩展方法来代替。
这个改变,主要原因是通过EnumerateFiles返回IEnumerable<string>而非之前的GetFiles方法的string[]。由于有一个地方必须使用string[],不然就会对代码造成很大影响,所以只好实现了自己的方法:
public static string[] GetFiles(string dir) { var names = Directory.EnumerateFiles(dir); List<string> lst = new List<string>(names); return lst.ToArray(); } public static string[] GetDirectories(string dir) { var names = Directory.EnumerateDirectories(dir); List<string> lst = new List<string>(names); return lst.ToArray(); }
当然,在大部分情况,还是建议直接使用EnumerateFiles方法和EnumerateDirectories方法。
在.NET中可以通过System.IO.Compression命名空间来读写zip文件,当然也可以用SharpZipLib。
在Silverlight中如果仅仅想读取zip文件的内容,可以把zip作为Content添加到xap中,然后用如下代码来读取其中的文件:
var zipfile = Application.GetResourceStream(new Uri("LCADB/entries_ILCD.zip",UriKind.Relative)); var xmlfile = Application.GetResourceStream(zipfile, new Uri("Locations_ILCD.xml",UriKind.Relative)); List<Location> lst = SerializationHelper.FromXml<List<Location>>(xmlfile.Stream);
用Application.GetResourceStream访问压缩文件的更详细的信息,见:
http://www.silverlightexamples.net/post/How-to-Get-Files-From-Resources-in-Silverlight-20.aspx
要写zip文件,就没有现成的函数库可用了,不过幸好有人把SharpZipLib移植到了Silverlight上,见:
http://slsharpziplib.codeplex.com/