How do I tell if a class can be serialized? - c#

I'm looping through the Session keys and adding entries and their values to a Hashtable, which I'm then serializing. The problem I'm having is there is an object on the Session that is not serializable, and it shouldn't be serialized anyway. I'm looking around, and plenty of built-in types don't implement the ISerializable attribute, so testing for that doesn't work:
if (val is ISerializable)
{
...
}
So, how do I test for this? Does this make sense?

There is only one guaranteed way to determine if an object is serializable. Serialize it and see if the operation succeeds.
I know that seems a bit overkill but there are just so many different ways that serialization can be broken. There are two items in Metadata you can check to see if a type claims serializability (ISerializable and [Serializable]) but this is just a claim. It can and is broken in so many different ways.
The problem is that in the .Net world the act of declaring the ability to be serialized and actually serializing are 2 separate distinct actions. It's perfectly possible (and legal) to do one but not the other. Take this for example
[Serializable]
public class Foo {
public Object Field1;
}
This class claims to be serializable and may very well be. It all depends on the value actually stored in Field1. No amount of metadata inspection on the type will every tell you whether it can actually be serialized. All you can do is try and see if it suceeds.

You can use the IsSerializable property of the Type class.
if(val.GetType().IsSerializable)

Check the same thing that CRL would use: the [Serializable] attribute.

Related

C# Serialization limitations

i want to implement a general Memento-Pattern in C#. It is working fine but i use the Serializeable() Attribute to do a deep copy of a object. My implementation using generics so if someone use it he has to give his class as type.
Now the class from user must have the Attribute Serializeable() too. Are there any limitations for a class which using Serializeable()?
In fact:
Are there any performance problems?
Is it possible to use an interface?
Is it possible to use inerhitence?
Is it possible to use Auto-Properties?
I dont know how the Attribute works and so iam a bit scary of using this in such a global way.
regards
for small models that you are cloning in memory, not usually
irrelevent; when using [Serializable] you are typically using BinaryFormatter - which looks at the objects themselves; it doesn't matter what interfaces they implement - the interfaces are not used
yes, for the same reason - but all types in the model must be [Serializable]
yes, for the same reason; note : the default BinaryFormatter implementation is looking at fields - it won't even touch the properties
Personally, I try to advise against BinaryFormatter, but this is perhaps not an unreasonable use. However! Be careful that it is easy to suck extra objects into the model accidentally, must commonly through events. Note that it is a good idea to mark all events as non-serialized:
[field:NonSerialized]
public event EventHandler Something;
(or apply to the field directly if using explicit add/remove accessors)
Note also that any members like:
public object Tag {get;set;} // caller-defined
should also probably be [field:NonSerialized].
Personally, I'd prefer a different serializer, but: this will often work. I will say, though: try to avoid persisting the output of BinaryFormatter, as it is hard to guarantee compatibility between revisions of your code.
I dont know how the Attribute works
It does nothing at all except add an IL flag that says "by the way, consider this ok to be serialized"; actually, most serializers don't even look at this flag - but BinaryFormatter is one of the few that do look at this flag. The real code here is BinaryFormatter, which basically does:
have I seen this object before? if so, store the key only
what type is it? is it [Serializable]? store the type info
invent a new reference and store that as the identity
does it have a custom serializer? if so: use that
what fields does it have? access each in turn and store the name/value pair

JSON.NET - exclude properties of a specific type at runtime

I'm wondering how to exclude/strip certain properties of given type(s) (or collections of those) from being serialized using Json.NET library?
I tried to write my own contract resolver (inheriting from DefaultContractResolver) with no luck.
I know that I could be done using DataAnnotations, decorating the excluded properties with ScriptIgnoreAttribute, but it's not applicable in my scenario. The objects serialized can be virtually anything, so I don't know which properties to exclude at design-time. I know only the types of properties that should not be serialized.
It looks like a rather simple task, but unfortunately I couldn't find a decent solution anywhere...
BTW - I'm not bound to Json.NET library - if it can easily be done with default/other .NET JSON serializers it'd be an equally good solution for me.
UPDATE
The properties has to be excluded before trying to serialize them. Why?
Basically, the types of objects I'm receiving and serializing can have dynamic properties of type inheriting from IDynamicMetaObjectProvider. I'm not going to describe all the details, but the DynamicMetaObject returned from GetMetaObject method of these objects doesn't have DynamicMetaObject.GetDynamicMemberNames method implemented (throws NotImplementedException...). Summarizing - the problem is those objects (I need to exclude) doesn't allow to enumerate their properties, what Json.NET serializer tries to do behind the scenes. I always end up with NotImplementedException being thrown.
I have tried both the WCF JSON serialization as well as the System.Web.Script.Serialization.JavaScriptSerializer. I have found if you want solid control of the serialization process and do not want to be bound by attributes and hacks to make things work, the JavaScriptSerializer is the way to go. It is included in the .NET stack and allows you to create and register JavaScriptConverter subclasses to perform custom serialization of types.
The only restriction I have found that may cause you a problem is that you cannot easily register a converter to convert all subclasses of Object (aka, one converter to rule them all). You really need to have knowledge of common base classes or preregister the set of types up front by scanning an assembly. However, property serialization is entirely left up to you, so you can decide using simple reflection which properties to serialize and how.
Plus, the default serialization is much much much better for JSON than the WCF approach. By default, all types are serializable without attributes, enums serialize by name, string-key dictionaries serialize as JSON objects, lists serialize as arrays, etc. But for obvious reasons, such as circular trees, even the default behavior needs assistance from time to time.
In my case, I was supporting a client-API that did not exactly match the server class structure, and we wanted a much simpler JSON syntax that was easy on the eyes, and the JavaScriptSerializer did the trick every time. Just let me know if you need some code samples to get started.
Create your own contract resolver, override the method that creates the properties for an object and then filter the results to only include those that you want.
Have you considered using the ShouldSerialize prefix property to exclude the property of your specific type at runtime?
public class Employee
{
public string Name { get; set; }
public Employee Manager { get; set; }
public bool ShouldSerializeManager()
{
return (Manager != this);
}
}

How to store User defined data type through DataContext?

I used DataContractSerializer to save user data but now
I want to use DataContext for my database design.
But the system existed struture as below cannot be stored through DataContext.
class Data
{
public DataType1;
public DataType2;
}
It seems these APIs cannot support storing user defined data type.
I don't want to separate all data members because this system uses these structure every where. If I changed the structure, it is hard to maintain and the DataType1 contains a List<> member. I don't know how to do even though separating
this structure.
Could you please kindly to give me some suggestions?
Thanks.
It seems these APIs cannot support storing user defined data type
If that were true the api would be completely without purpose.
The DataContractSerializer has what appear to be conflicting rules in an attempt to make serialisation more implicit. You can for example serialise a public type that has public properties and a public default constructor without having to decorate it with a DataContract attribute or any of its members with a DataMember attribute.
Looks to me that at the very least you need make Data a public class. Most likely you would need to review your other classes to ensure that either they are implicitly serializable or that you explictly mark them up with the DataContract and DataMember attributes.
Dear all:
But now I used DataContext
DataContext cannot serialize the user defined type even marked [Serializable].
The workaround seems to separate all the members into one class now.....
Thanks.

Deserializing individual objects

Is there a way in .Net 4 to easily deserialize a stream of mixed objects one by one? I can read to the start of the element for an object I want to deserialize using XmlTextReader.Read(), but have tried many ways to deserialize that specific object unsuccessfully.
The types I want to deserialize can be read as a list of those types without a problem using XmlSerializer, however I want to be able to mix them rather than having input files containing just lists of one object type.
e.g.
<Objects>
<TypeA>...</TypeA>
<TypeB>...</TypeB>
<TypeA>...</TypeA>
<TypeC>...</TypeC>
...
</Objects>
The ordering of the objects in would be random.
Many thanks for any pointers.
I've looked at XmlSerializer, DataContractSerializer and XElement, but could not get them to work for this (although I possibly didn't set those up correctly as I'm not very familiar with them).
You can do that with the XmlSerializer.
However, be careful with the following:
The array you are serializing/deserializing must be declared as an array of "object" (or the base object if all other types inherit from it)
Each type will have "xsi:type" attached to it
You must use [XmlInclude] to include all the type(s) you are ever going to need with the "root" object.
The need to [XmlInclude] all the object types mean that you're not going to be able to dynamically add types to the serialization. You'll need to add [XmlInclude]'s and recompile to include the new type(s).
Your XML, however, will become:
<Objects>
<TypeObj xsi:type="TypeA">...</TypeObj>
<TypeObj xsi:type="TypeB">...</TypeObj>
<TypeObj xsi:type="TypeA">...</TypeObj>
<TypeObj xsi:type="TypeC">...</TypeObj>
:
</Objects>
This is the most flexible and "normal" way of approach XML serialization of multiple types. However, if you need to keep your exact format, you can declare your class this way:
[XmlRoot("Objects")]
public class Objects
{
[XmlElement("TypeA")] public TypeA[] TypeAObjects;
[XmlElement("TypeB")] public TypeB[] TypeBObjects;
[XmlElement("TypeC")] public TypeC[] TypeCObjects;
:
}
[XmlElement] means that all the objects are jumbled up on the same level (different from XmlArray). They do not even have to be in order.
The pitfalls of doing this, however, is that if you want to add a new type, you'll have to modify the "Objects" class.
Not sure if this is helpful, but it might be an idea to take a look at how RestSharp does their deserialization. https://github.com/johnsheehan/RestSharp
Specifilcally Take a look at RestSharp/Deserializers/XmlDeserializer.cs
You would need to create an XmlSerializer for each type. How many types you have and how many times each would get used would determine if it's better to create a new XmlSerializer for each object as you process it, or store them in a Dictionary<string, XmlSerializer> to be reused. The XmlSerializer takes the type in its constructor, and then you can call the Deserialize method, passing it a StringReader that contains the XML string you read from your file. Hopefully that's enough to get you started, but if you need more help I can throw together some sample code ;)

Renaming fields then deserializing in C#

I have data stored in an instance of a class which has been serialized with the .net BinaryFormatter. I now want to rename one of the fields in the class, but still be able to deserialize the old data.
One option is to implement ISerializable and deserialize all the the fields of the class manually. But this seems like a lot of work, especially if my class has lots of fields and I've only renamed a single field.
Is there a better way?
Craig suggests keeping a copy of the old class for deserialization, and copying values to the new class. I've seen this suggested elsewhere too - what advantage does this have over implementing ISerializable? As far as I can see, copying the class leaves me with 2 almost identical copies of the class plus I still have to copy all the values from the old class to the new class - which seems the same amount of work as implementing ISerializable with an almost duplicate class thrown into mix.
Two answers have mentioned Binders. I've successfully used a SerializationBinder to deserialize a class Bar which was Serialized as class Foo, but that's because the name of the class changed. Does SerializationBinder also help when you've renamed a field - say when int m_Left has been renamed to int m_Right?
Yes, this is the problem with field-based serializers. You can use either a custom Binder, or a "serialization surrogate" to avoid implementing ISerializable, but that is only a case-by-case fix.
I've discussed this topic (in the context of obfuscators, and auto-props) here. My advice is: don't use BinaryFormatter for persistance of data between versions... for that, look at contract-based serializers:
XmlSerializer
DataContractSerializer
or for binary, things like protobuf-net
None of this helps you today, but it might help you design around it in the future.
You could try having the old calss hang around for the sole purpose of rehydration and then just copy over the fields you need to the new class. Still kind of painful but should work.
I used SerializationBinder class for this before
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder.aspx
it can be used for deserialization so you can remap old type to new one.
What if you just change the access modifier on that one property to private, and then have a public property with the new name that just basically wraps the old one. That way you should still be able to deserialize (I THINK) but anyone using this class won't know about the old name. Just a thought...

Categories

Resources