任何人都可以推荐一种方法来检查一个类是否可以序列化为XML?

jam*_*iet 6 .net c# windows-runtime

我有一个Generic类,它接受类型为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#方言有关.

提前致谢

杰米

Chr*_*air 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:由于您在 save 方法中做了很多其他工作,我建议像这样重写您的代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以专门捕获序列化问题,并可以非常清楚地向 API 使用者报告他们提供了无效/不可序列化的对象。这样,如果 I/O 部分抛出异常,问题出在哪里就会更清楚。事实上,您可能希望将序列化/反序列化方面分离到它们自己的离散方法/类中,以便您可以输入其他序列化程序(或者从堆栈跟踪中更清楚问题所在,或者只是让您的方法执行一项操作)事情而且只有一件事)但是无论如何,任何更多的重写/重构实际上都留给代码审查,并且对于手头的问题没有多大作用。

仅供参考,我还对您的输入对象进行了空检查,因为如果用户传递空值,他们会认为保存成功,而实际上什么也没发生,并且他们可能期望稍后可以加载一个值,但实际上没有存在。如果您希望允许空值作为有效值,则不必担心检查会引发错误。