Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can anyone recommend a way to check if a class can be serialized as XML?

I have a Generic class that takes an object of type T, serializes it as XML, then saves it to the filesystem. Currently however the serialize operation fails if the object is not serializable. That's not a problem as such, however I think it would be better to check in my class constructor whether an instance of T is serializable or not and if it is not, throw an error at that point rather than later on.

Is there a way of checking of an instance of T can be serialized as XML other than simply instantiating it and trying to serialize it in a TRY...CATCH? It would be nice if I could interrogate the class T in some manner to discover whether it can be serialized as XML or not.

If it helps, the code can be seen here: http://winrtstoragehelper.codeplex.com/SourceControl/changeset/view/ac24e6e923cd#WinRtUtility%2fWinRtUtility%2fObjectStorageHelper.cs

Note that this code gets compiled against WinRT (i.e., it is for use in a Windows 8 app) however I think the question is relevant to any dialect of C#.

thanks in advance

Jamie

like image 542
jamiet Avatar asked Sep 04 '12 20:09

jamiet


People also ask

Which is the correct way of using XML serialization?

As with the CreatePo method, you must first construct an XmlSerializer, passing the type of class to be deserialized to the constructor. Also, a FileStream is required to read the XML document. To deserialize the objects, call the Deserialize method with the FileStream as an argument.

Which class should be used to serialize an object in XML format?

You should basically use System. Xml. Serialization. XmlSerializer class to do this.

What does it mean to serialize XML?

XML serialization is the process of converting XML data from its representation in the XQuery and XPath data model, which is the hierarchical format it has in a Db2® database, to the serialized string format that it has in an application.


2 Answers

AFAIK, even if you check for various attributes (Serializable, DataContract) or check for the Type.IsSerializable (which I believe is just a convenience method for checking the Serializable attribute's existence) it doesn't guarantee that the implementation actually is serializable. (EDIT: As mentioned, and seen in the example code provided in the question, XmlSerializer does not depend on the Serializable attribute adornment. So there's no sense in checking for these flags.)

In my experience, your best bet is to use unit tests that will validate the various types used in your application and use try/catch to see if it pass/fails. At runtime, use try/catch (rather than pre-checking each time) and log/handle the exception.

If you have a list of valid compatible types as a result of your unit-testing, you can have a pre-check of T against a compile-time list that you determined from testing previously and assume any other types are just no good. Might want to watch for subclasses of known valid types though as even if they inherit from a valid serializable type, their implementation may not be.

EDIT: Since this is for Windows Phone 8, while I don't have experience with that platform, I have worked with Silverlight. And in that case, you can serialize objects even if they are not marked as [Serializable] (in fact, it doesn't even exist in Silverlight). The built-in XmlSerializer just works against all public properties regardless of adornment. The only way to see if it's serializable is either attempt a serialization and try/catch the failure, or write an algorithm to inspect each property (and recursively through child objects) and check if each type can be serialized.

EDITx2: Looking at your ObjectStorageHelper, I would suggest that you simply attempt serialization and catch any failures. You don't necessarily have to bubble up the exception directly. You could wrap with your own custom exception or have a returned results object that informs the API consumer of the pass/fail of the serialization and why it may have failed. Better to assume the caller is using a valid object rather than doing an expensive check each time.

EDITx3: Since you're doing a lot of other work in the save method, I would suggest rewriting your code like this:

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();
    }
}

This way you catch the serialization issue specifically and can report to the API consumer very clearly that they have provided an invalid/non-serializable object. This way if you have an exception being thrown as part of your I/O portions, it's clearer where the issue is. In fact, you may want to separate out the serialization/deserialization aspects to their own discrete method/class so you can feed in other serializers (or be more clear from the stack trace where the issue is, or simply to make your methods do one thing and one thing only) But any more rewriting/refactoring is really left for code-review anyway and not valid much for the question at hand.

FYI, I also put a null check for your input object because if the user passes null, they would think that the save was successful when in fact, nothing happened and they might expect a value to be available for loading later when it doesn't exist. If you want to allow nulls as valid values, then don't bother with the check throwing an error.

like image 136
Chris Sinclair Avatar answered Sep 30 '22 15:09

Chris Sinclair


It depends on what "can be serialized" means. Any class can be serialized with XmlSerializer. If what you mean by can be serialized is that no error occurs, then you'll have to try and catch exceptions to tell for sure.

like image 31
Peter Ritchie Avatar answered Sep 30 '22 17:09

Peter Ritchie