据我所知,即使您检查各种属性(如
Serializable
、
DataContract
),或者检查
Type.IsSerializable
(我认为这只是一个检查
Serializable
属性是否存在的便捷方法),也不能保证实现实际上是可序列化的。
(编辑:正如提问中提供的示例代码所示,XmlSerializer
不依赖于Serializable
属性修饰。因此,检查这些标志是没有意义的。)
根据我的经验,最好的方法是使用单元测试来验证应用程序中使用的各种类型,并使用try/catch来查看它是否通过/失败。在运行时,使用try/catch(而不是每次预先检查)并记录/处理异常。
如果您有一个有效兼容类型列表作为单元测试的结果,可以对编译时从先前测试中确定的列表中的
T
进行预检查,并假设任何其他类型都是无用的。但要注意已知有效类型的子类,因为即使它们继承自有效的可序列化类型,它们的实现也可能不是。
编辑:由于这是针对Windows Phone 8的,虽然我没有在该平台上的经验,但我曾经使用过Silverlight。在这种情况下,即使它们没有标记为
[Serializable]
(事实上,在Silverlight中它甚至不存在),您也可以序列化对象。内置的
XmlSerializer
只针对所有公共属性工作,而不考虑修饰。检查它是否可序列化的唯一方法是尝试序列化并尝试/捕获失败,或编写一个算法来检查每个属性(以及递归到子对象)并检查每个类型是否可以序列化。
编辑x2:查看您的
ObjectStorageHelper
,我建议您只需尝试序列化并捕获任何失败即可。您不一定要直接传递异常。您可以使用自己的自定义异常进行包装,或者返回结果对象,通知API使用者序列化的通过/失败及其可能失败的原因。最好
假设调用者正在使用有效的对象,而不是每次都进行昂贵的检查。
编辑x3:由于您在保存方法中做了很多其他工作,我建议您像这样重写代码:
public async Task SaveAsync(T Obj)
{
if (Obj == null)
throw new ArgumentNullException("Obj");
StorageFile file = null;
StorageFolder folder = GetFolder(storageType);
file = await folder.CreateFileAsync(FileName(Obj), CreationCollisionOption.ReplaceExisting);
IRandomAccessStream writeStream = await file.OpenAsync(FileAccessMode.ReadWrite);
using (Stream outStream = Task.Run(() => writeStream.AsStreamForWrite()).Result)
{
try
{
serializer.Serialize(outStream, Obj);
}
catch (InvalidOperationException ex)
{
throw new TypeNotSerializableException(typeof(T), ex);
}
await outStream.FlushAsync();
}
}
这样可以捕获序列化问题,并明确向API使用者报告他们提供了一个无效/不可序列化的对象。如果I/O部分抛出异常,则更清晰地知道问题所在。实际上,您可能希望将序列化/反序列化方面分离为自己的离散方法/类,以便可以输入其他序列化器(或从堆栈跟踪中更清楚地知道问题所在,或者仅使您的方法只执行一项任务)。但是任何更多的重写/重构都要留给代码审查,而不是针对手头的问题有效。
另外,我还对您的输入对象进行了空值检查,因为如果用户传递null,则会认为保存成功,而实际上什么也没有发生,并且他们可能期望稍后加载时有一个值可用,但实际上它不存在。如果您想允许null作为有效值,则不需要检查并引发错误。