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 部分中抛出异常,那么问题出在哪里就更清楚了。实际上,您可能希望将序列化/反序列化方面分离到它们自己的离散方法/类中,以便您可以输入其他序列化程序(或者从堆栈跟踪中更清楚问题所在,或者只是让您的方法做一个一件事和一件事)但是无论如何,任何更多的重写/重构实际上都留给代码审查,并且对于手头的问题没有多大意义。
仅供参考,我还为您的输入对象设置了一个空值检查,因为如果用户传递空值,他们会认为保存成功,而事实上,没有发生任何事情,他们可能期望一个值当它不存在时可用于稍后加载。如果你想允许空值作为有效值,那么不要为 check 抛出错误而烦恼。