积极答复者
如何在一个JS metro app 引用的 C#组件中序列化一个包含List<T>的类?

问题
-
之前我在英文论坛也提过问题,虽然得到了一些思路,但是仍然无法解决这个问题
首先我正在开发一个JS metro app,后来引用了一个自定义的C#组件,用来进行数据定义和序列化等操作,C#组件的输出类型是winMD,我定义了一个BOOK类:
public sealed class Book
{
public string ID{ get; set; }
public string Title { get; set; }
public string Creator { get; set; }public List<Chapter> Chapters { get; set; }
public Book()
{
this.Chapters = new List<Chapter>();
}}
其中Chapter是另一个类,这里就不写出来了,和BOOK类类似。但是我发现当我定义public List<Chapter> Chapters { get; set; }时报出了异常,异常说的是List<T>是一个CLR类型,不是合法的WINRT类型,然后让我用IList<T>代替,于是我就照做了。
public sealed class Book
{
public string ID{ get; set; }
public string Title { get; set; }
public string Creator { get; set; }public IList<Chapter> Chapters { get; set; }
public Book()
{
this.Chapters = new List<Chapter>();
}一切正常,之后开始写序列化类,打算把BOOK类的一个实例序列化,但是这时候问题就出现了,下面是我的序列化类
public async void XMLSerialize(StorageFolder folder, string fileName, object instance, Type type)
{
XmlSerializer serializer = null;
try
{
serializer = new XmlSerializer(type);
}
catch (Exception ex)
{
}
StorageFile newFile = await FileHelper.CreateFile(folder, fileName);
Stream newFileStream = await newFile.OpenStreamForWriteAsync();
serializer.Serialize(newFileStream, instance);
newFileStream.Dispose();
}}
上面代码会catch出一个异常,就是serializer = new XmlSerializer(type);无法序列化一个接口,因为我的IList是个接口所以无法序列化。
我去很多地方提问,英文论坛版主回复我的是将BOOK类改为internal,就可以使用LIST〈T〉了,我就试了一下,但是internal的含义是本程序集可访问,也就是说当我执行
serializer = new XmlSerializer(type);的时候因为type是BOOK类型,而BOOK是internal的而XmlSerializer 是System.Xml.Serialization的,所以我不能用BOOK类型来
构造我的XmlSerializer ,这样问题又回来了。
我想序列化就必须用LIST〈T〉,但是他不是WINRT的类型所以我不能用,使用internal关键字之后又无法构造XmlSerializer 也就是无法序列化了,这样我就陷入了一个死循环。
跪求论坛里的各位大神帮帮忙,帮我想个办法怎么解决这个问题。不会最后就要手动写序列化方法了吧。
答案
-
首先,肯定一点,用IList<T>接口没错,否则内部类无法构造XmlSerializer 导致无法序列化。我写过类似的序列化,我是这么处理的:
使用 DataContractSerializer 类来做的,而不是XmlSerializer。
public static IAsyncAction serialization() { return AsyncInfo.Run(async (token) => { try { StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting); IRandomAccessStream raStream = await file.OpenAsync(FileAccessMode.ReadWrite); using (IOutputStream outStream = raStream.GetOutputStreamAt(0)) { // Serialize the Session State. DataContractSerializer serializer = new DataContractSerializer(typeof(type)); serializer.WriteObject(outStream.AsStreamForWrite(), instance); await outStream.FlushAsync(); } } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message); } }); }
但是注意,如此序列化后IList会最后被反序列化成数组形式,可能会导致你的JS在调用时发生问题。所以我的解决方法是在反序列化后,你的IList属性虽然接到了一个数组,但是你可以在属性的get方法中遍历这个数组将其在转化为List对象。比如我之前写的这个属性:
[DataMember] private IList<string> _searchHistory = new List<string>(); public IList<string> searchHistory { get { // change the deserialize search history string array data to IList if (_searchHistory is string[]) { string[] dsHistory = _searchHistory as string[]; _searchHistory = new List<string>(); foreach (string s in dsHistory) _searchHistory.Add(s); } // end of the change return _searchHistory; } }
Bob Bao [MSFT]
MSDN Community Support | Feedback to us
- 已建议为答案 Jie BaoModerator 2012年5月10日 4:11
- 已标记为答案 illegalusername 2012年5月10日 8:18
全部回复
-
之前我在英文论坛也提过问题,虽然得到了一些思路,但是仍然无法解决这个问题
首先我正在开发一个JS metro app,后来引用了一个自定义的C#组件,用来进行数据定义和序列化等操作,C#组件的输出类型是winMD,我定义了一个BOOK类:
public sealed class Book
{
public string ID{ get; set; }
public string Title { get; set; }
public string Creator { get; set; }public List<Chapter> Chapters { get; set; }
public Book()
{
this.Chapters = new List<Chapter>();
}}
其中Chapter是另一个类,这里就不写出来了,和BOOK类类似。但是我发现当我定义public List<Chapter> Chapters { get; set; }时报出了异常,异常说的是List<T>是一个CLR类型,不是合法的WINRT类型,然后让我用IList<T>代替,于是我就照做了。
public sealed class Book
{
public string ID{ get; set; }
public string Title { get; set; }
public string Creator { get; set; }public IList<Chapter> Chapters { get; set; }
public Book()
{
this.Chapters = new List<Chapter>();
}一切正常,之后开始写序列化类,打算把BOOK类的一个实例序列化,但是这时候问题就出现了,下面是我的序列化类
public async void XMLSerialize(StorageFolder folder, string fileName, object instance, Type type)
{
XmlSerializer serializer = null;
try
{
serializer = new XmlSerializer(type);
}
catch (Exception ex)
{
}
StorageFile newFile = await FileHelper.CreateFile(folder, fileName);
Stream newFileStream = await newFile.OpenStreamForWriteAsync();
serializer.Serialize(newFileStream, instance);
newFileStream.Dispose();
}}
上面代码会catch出一个异常,就是serializer = new XmlSerializer(type);无法序列化一个接口,因为我的IList是个接口所以无法序列化。
我去很多地方提问,英文论坛版主回复我的是将BOOK类改为internal,就可以使用LIST〈T〉了,我就试了一下,但是internal的含义是本程序集可访问,也就是说当我执行
serializer = new XmlSerializer(type);的时候因为type是BOOK类型,而BOOK是internal的而XmlSerializer 是System.Xml.Serialization的,所以我不能用BOOK类型来
构造我的XmlSerializer ,这样问题又回来了。
我想序列化就必须用LIST〈T〉,但是他不是WINRT的类型所以我不能用,使用internal关键字之后又无法构造XmlSerializer 也就是无法序列化了,这样我就陷入了一个死循环。
跪求论坛里的各位大神帮帮忙,帮我想个办法怎么解决这个问题。不会最后就要手动写序列化方法了吧。
- 已移动 chenrensong 2012年5月9日 3:42 关于windows 8 metro 程序开发的问题! (发件人:Visual C#)
- 已合并 Jie BaoModerator 2012年5月10日 3:45 duplicate
-
首先,肯定一点,用IList<T>接口没错,否则内部类无法构造XmlSerializer 导致无法序列化。我写过类似的序列化,我是这么处理的:
使用 DataContractSerializer 类来做的,而不是XmlSerializer。
public static IAsyncAction serialization() { return AsyncInfo.Run(async (token) => { try { StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting); IRandomAccessStream raStream = await file.OpenAsync(FileAccessMode.ReadWrite); using (IOutputStream outStream = raStream.GetOutputStreamAt(0)) { // Serialize the Session State. DataContractSerializer serializer = new DataContractSerializer(typeof(type)); serializer.WriteObject(outStream.AsStreamForWrite(), instance); await outStream.FlushAsync(); } } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message); } }); }
但是注意,如此序列化后IList会最后被反序列化成数组形式,可能会导致你的JS在调用时发生问题。所以我的解决方法是在反序列化后,你的IList属性虽然接到了一个数组,但是你可以在属性的get方法中遍历这个数组将其在转化为List对象。比如我之前写的这个属性:
[DataMember] private IList<string> _searchHistory = new List<string>(); public IList<string> searchHistory { get { // change the deserialize search history string array data to IList if (_searchHistory is string[]) { string[] dsHistory = _searchHistory as string[]; _searchHistory = new List<string>(); foreach (string s in dsHistory) _searchHistory.Add(s); } // end of the change return _searchHistory; } }
Bob Bao [MSFT]
MSDN Community Support | Feedback to us
- 已建议为答案 Jie BaoModerator 2012年5月10日 4:11
- 已标记为答案 illegalusername 2012年5月10日 8:18