6

我有一个通用类,它采用 T 类型的对象,将其序列化为 XML,然后将其保存到文件系统。但是,目前如果对象不可序列化,则序列化操作将失败。这本身不是问题,但是我认为最好在我的类构造函数中检查 T 的实例是否可序列化,如果不是,则在此时而不是稍后抛出错误。

有没有一种方法可以检查 T 的实例是否可以序列化为 XML,而不是简单地实例化它并尝试在 TRY...CATCH 中对其进行序列化?如果我能以某种方式询问类 T 以发现它是否可以序列化为 XML,那就太好了。

如果有帮助,可以在此处查看代码:http ://winrtstoragehelper.codeplex.com/SourceControl/changeset/view/ac24e6e923cd#WinRtUtility%2fWinRtUtility%2fObjectStorageHelper.cs

请注意,此代码是针对 WinRT 编译的(即,它用于 Windows 8 应用程序)但是我认为这个问题与 C# 的任何方言有关。

提前致谢

杰米

4

2 回答 2

4

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 部分中抛出异常,那么问题出在哪里就更清楚了。实际上,您可能希望将序列化/反序列化方面分离到它们自己的离散方法/类中,以便您可以输入其他序列化程序(或者从堆栈跟踪中更清楚问题所在,或者只是让您的方法做一个一件事和一件事)但是无论如何,任何更多的重写/重构实际上都留给代码审查,并且对于手头的问题没有多大意义。

仅供参考,我还为您的输入对象设置了一个空值检查,因为如果用户传递空值,他们会认为保存成功,而实际上没有发生任何事情,并且他们可能希望稍后可以加载一个值存在。如果您想允许空值作为有效值,则不要为检查引发错误而烦恼。

于 2012-09-04T20:06:42.977 回答
2

这取决于“可以序列化”是什么意思。任何类都可以用XmlSerializer. 如果您所说的可以序列化是没有错误发生,那么您必须尝试捕获异常才能确定。

于 2012-09-04T20:13:22.357 回答