C# 有人能推荐一种方法来检查类是否可以序列化为XML吗?

C# 有人能推荐一种方法来检查类是否可以序列化为XML吗?,c#,.net,windows-runtime,C#,.net,Windows Runtime,我有一个泛型类,它接受T类型的对象,将其序列化为XML,然后将其保存到文件系统。但是,当前,如果对象不可序列化,序列化操作将失败。这本身不是问题,但是我认为最好在我的类构造函数中检查T的实例是否可序列化,如果不是,则在该点抛出错误,而不是稍后抛出错误 是否有一种方法可以检查T的实例是否可以序列化为XML,而不是简单地实例化它并尝试在TRY…CATCH中序列化它?如果我能以某种方式询问类T,以发现它是否可以序列化为XML,那就太好了 如果有帮助,可在此处查看代码: 请注意,这段代码是针对WinRT

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

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

如果有帮助,可在此处查看代码:

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

提前谢谢


Jamie

AFAIK,即使您检查各种属性(
Serializable
DataContract
)或检查
类型.IsSerializable
(我认为这只是检查
Serializable
属性存在的一种方便方法)它不能保证实现实际上是可序列化的。(编辑:如前所述,并在问题中提供的示例代码中看到,
XmlSerializer
不依赖于
Serializable
属性装饰。因此检查这些标志毫无意义。)

根据我的经验,最好的办法是使用单元测试来验证应用程序中使用的各种类型,并使用try/catch来查看它是否通过/失败。在运行时,使用try/catch(而不是每次都预先检查)并记录/处理异常

如果您有一个有效兼容类型的列表作为单元测试的结果,那么您可以根据编译时列表预先检查
T
,该列表是您之前通过测试确定的,并且假设任何其他类型都不好。可能希望监视已知有效类型的子类,尽管即使它们继承自有效的可序列化类型,它们的实现也可能不是

编辑:由于这是针对WindowsPhone8的,虽然我没有使用该平台的经验,但我使用过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();
    }
}
通过这种方式,您可以专门捕获序列化问题,并可以非常清楚地向API使用者报告他们提供了无效/不可序列化的对象。这样,如果在I/O部分抛出异常,问题所在就更清楚了。事实上,您可能希望将序列化/反序列化方面分离到它们自己的离散方法/类中,以便可以输入其他序列化程序(或者从堆栈跟踪中更清楚问题所在,或者简单地让您的方法只做一件事)但是,任何更多的重写/重构实际上都是留给代码审查的,对于手边的问题来说都不太有效


仅供参考,我还为您的输入对象设置了null检查,因为如果用户传递null,他们会认为保存成功,而实际上什么都没有发生,并且他们可能希望在不存在值的情况下可以稍后加载该值。如果您想允许空值作为有效值,那么就不要麻烦检查抛出错误。

这取决于“可以序列化”的含义。任何类都可以使用
XmlSerializer
进行序列化。如果您所说的可以序列化是指没有错误发生,那么您必须尝试捕获异常以确定是否发生。

如果您只想检查类是否用SerializableAttribute修饰,请使用typeof(T)。GetCustomAttributes(typeof(SerializableAttribute),false)Hi Leffebrene,感谢您的回复。不,我不想简单地检查它是否具有该属性。我对其他一些回复的评论很有希望解释为什么不能。嗨,克里斯,听起来是个不错的建议,但是考虑到我希望它适用于几乎所有的T类(这是一个类库,我希望其他人会使用它-我没有积极地用它来构建应用程序)我真的不想只局限于我已经验证过的可以在单元测试中序列化的子集类型。希望这是有道理的。JT
最好假设调用方使用的是有效对象,而不是每次都进行昂贵的检查。
好的建议+1
XmlSerializer
不需要
SerializableAttribute
来序列化类的实例。@jamiet完全需要。请参阅我最新的“EDITx2”。本质上,让API的使用者负责确保其类型是可序列化的。如果他们给你垃圾,处理它,要么抛出异常,要么按你的意愿向他们报告。只需记录可序列化的需求(也许您可以提到您希望它们与
XmlSer兼容)