AFAIK,即使您检查各种属性(Serializable
, DataContract
)或检查Type.IsSerializable
(我认为这只是检查Serializable
属性存在的一种方便方法),它也不能保证实现实际上是可序列化的。(编辑:如前所述,并在问题中提供的示例代码中看到,XmlSerializer
不依赖于Serializable
属性装饰。因此检查这些标志是没有意义的。)
根据我的经验,最好的办法是使用单元测试来验证应用程序中使用的各种类型,并使用 try/catch 来查看它是否通过/失败。在运行时,使用 try/catch(而不是每次都预先检查)并记录/处理异常。
如果您有一个作为单元测试结果的有效兼容类型列表,您可以根据您之前从测试中确定的编译时列表进行预检查,T
并假设任何其他类型都不好。可能想要注意已知有效类型的子类,即使它们继承自有效的可序列化类型,它们的实现也可能不是。
编辑:由于这是针对 Windows Phone 8 的,虽然我没有使用该平台的经验,但我使用过 Silverlight。在这种情况下,您可以序列化对象,即使它们没有被标记为[Serializable]
(事实上,它甚至在 Silverlight 中都不存在)。XmlSerializer
无论装饰如何,内置仅适用于所有公共属性。查看它是否可序列化的唯一方法是尝试序列化并尝试/捕获故障,或者编写算法来检查每个属性(并通过子对象递归)并检查每种类型是否可以序列化。
EDITx2:看看你的ObjectStorageHelper
,我建议你简单地尝试序列化并捕捉任何失败。您不一定要直接冒泡异常。您可以使用自己的自定义异常进行包装,或者返回一个结果对象,通知 API 使用者序列化的通过/失败以及它可能失败的原因。最好假设调用者使用的是有效对象,而不是每次都进行昂贵的检查。
EDITx3:由于您在保存方法中做了很多其他工作,我建议您像这样重写您的代码:
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 部分中抛出异常,那么问题出在哪里就更清楚了。实际上,您可能希望将序列化/反序列化方面分离到它们自己的离散方法/类中,以便您可以输入其他序列化程序(或者从堆栈跟踪中更清楚问题所在,或者只是让您的方法做一个一件事和一件事)但是无论如何,任何更多的重写/重构实际上都留给代码审查,并且对于手头的问题没有多大意义。
仅供参考,我还为您的输入对象设置了一个空值检查,因为如果用户传递空值,他们会认为保存成功,而实际上没有发生任何事情,并且他们可能希望稍后可以加载一个值存在。如果您想允许空值作为有效值,则不要为检查引发错误而烦恼。