Calling GetObjectData on serialization - c#

I am confused about the serialization sample from MSDN.
My confusion is in method GetObjectData (which is called during serialization), will the method,
serialize both the additional data (in method GetObjectData from AddValue) and the fields/properties of the class;
or just write the data in method GetObjectData without writing fields/properties of the class?
I have debugged seems (2) is correct -- no fields/properties data are serialized if GetObjectData method is used? Is that correct? (I am not an expert and just want to confirm here, but 100% confident about myself.)

Im not sure what you want to achieve but isn't easier to let C# do the work for you:
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace Test
{
[Serializable]
public class TestObject
{
private String name;
private String note;
#region Getters/setters
public String Name
{
get { return name; }
set { name = value; }
}
public String Note
{
get { return note; }
set { note = value; }
}
#endregion
}
}
Now you can use the XmlSerializer or BinaryFormatter to (de)serialize the object

If you implement ISerializable, you are reasponsible for all data (i.e. scenario "2" in your question); nothing extra is serialized automatically. What is your requirement? Things like DataContractSerializer can be property-based, allowing you to decorate both the regular fields and your custom property (that has some logic) and have them serialized properly. If you need binary (for space etc), then perhaps consider things like protobuf-net, which mixes the two while being space efficient.
So: what are your requirements?
Data Contract example:
[DataContract]
public class Foo {
[DataMember]
public int Bar {get;set;} // simple data
[DataMember]
private string DoSomeThinking {
get {.... serialize the complex data ....}
set {.... deserialize the complex data ....}
}
}

If you implement ISerializable you must add all data (at least the data needed to deserialize) including all fields to the SerializationInfo using AddValue.

Related

C# - Serializing List of Object to XML using generic method [duplicate]

I have a serializable class and one of the properties in my class generates a Guid in the getter. The property implements no setter and is ignores during serialization. Why is that and do I always have to implement a setter in order for my property to be serialized.
[Serializable]
public class Example
{
[XmlAttribute("id")]
public string Id
{
get
{
return Guid.NewGuid().ToString();
}
}
}
I tried implementing an empty setter and it got serialized correctly.
[Serializable]
public class Example
{
[XmlAttribute("id")]
public string Id
{
get
{
return Guid.NewGuid().ToString();
}
set {}
}
}
Update:
Can you point out how should I define properties whose values never change or ones that the value for is generated internally?
It's a limitation of XmlSerializer it doesn't serialize read-only properties, what you have done in your second example is essentially the hack to get it to serialize, however, it's useless if you need it to deserialize later.
Alternatively you could switch to using DataContractSerializer, it's more flexible.
See "Introducing XML Serialization" in the MSDN documentation. Among other things, it says:
Items That Can Be Serialized
The following items can be serialized using the XmlSerializer class:
Public read/write properties and fields of public classes.
Classes that implement ICollection or IEnumerable.
Note:
Only collections are serialized, not public properties.
XmlElement objects.
XmlNode objects.
DataSet objects.
Also, see "Why XML-Serializable class need a parameterless constructor"
Also, IXmlSerializable
In addition to the above types which can be serialized by the XML Serializer, any type which implements the IXmlSerializable interface can be serialized and deserialized. In particular, this means that the XElement and XDocument types can be serialized.
See "IXmlSerializable Interface".
Limitation of XMLSerializer - Properties without setter can't be serialized.
But you can use DataContractSerializer to serialize private setter properties -
[DataMember]
public string Id
{
get
{
return Guid.NewGuid().ToString();
}
private set {}
}
if you want to have private setters, and have the object be serializable/deserializable, impliment ISerializable, and create a constructor like MyObject(SerializationInfo info, StreamingContext context). An example is found here.
Serialization attributes are used to serialize and deserialize objects.
XmlSerializer will assume that you don't need to serialize any property that doesn't have a setter.
Setter will be used when deserializing a string into an object, because an instance of the object needs to be created and then the setter will be used to populate the property value.

NetDataContractSerializer Deserialization With New Property

Lacking any real foresight, I've serialized a large set of data decorated only with Serializable using NetDataContractSerializer, and now I'd like to add a new field. What are my options?
The original class looks something like this (with a few levels of inheritance and quite a few fields):
[Serializable]
public class InheritedClass : BaseClass
{
public string StringId { get; set; }
}
And now I'd like to add another property, say something like:
[Serializable]
public class InheritedClass : BaseClass
{
public string StringId { get; set; }
public int IntId { get; set; }
}
Now when I update the class and go to deserialize, I receive an exception since the new field is not present, something like:
Exception thrown: 'System.Runtime.Serialization.SerializationException' in System.Runtime.Serialization.dll
Additional information: Error in line 1 position 601. 'Element' '_x003C_StringId_x003E_k__BackingField' from namespace 'http://schemas.datacontract.org/2004/07/QT' is not expected. Expecting element '_x003C_IntId_x003E_k__BackingField'.
Ok, so this makes sense since NetDataContractSerializer requires the same class. I can get around that using a DataMember attribute like:
[DataMember(IsRequired = false)]
The problem then is that switching to DataMember (as I should have done upfront, or used a different serializer) changes the implicit alphabetical ordering, and then most of my fields will silently not deserialize as is well known.
I've attempted to add an ordering that's inline with the ordering on disk manually (via Order properties on the attribute), but that doesn't appear to be respected either. (I don't see an order value I could match in the raw xml either.)
Are there any other options beyond writing something to load the xml and insert the missing node? (Or equivalently setup a parallel type and deserialize from one an re-serialize to another?) If not, I'll probably just load up with the current type and deserialize to JsonNet or protobuf, but am I missing anything more straightforward with DataMember/etc?
Marking a type with [Serializable] means that the type can be serialized by serializing its public and private fields -- not its properties. NetDataContractSerializer respects this attribute when present, serializing the fields as indicated. For an auto-implemented property the secret backing field is what is actually serialized.
When adding a new field, what one generally does to handle legacy data is to mark it with [OptionalField] to indicate that it won't always be present in serialization streams. In c# 7.3 and later, it's possible to do this to the secret backing field of an auto-implemented property by using a field-targeted attribute:
[Serializable]
public class InheritedClass : BaseClass
{
public string StringId { get; set; }
[field: OptionalField]
public int IntId { get; set; }
}
Prior to c# 7.3 there is no way to apply an attribute to the backing field of an auto-implemented property. Thus you need to make the backing field be explicit and add the attribute to it:
[Serializable]
public class InheritedClass : BaseClass
{
public string StringId { get; set; }
[OptionalField]
int intId;
public int IntId { get { return intId; } set { intId = value; } }
}
Notes:
As noted in the question, if a type is marked with data contract attributes then NetDataContractSerializer will use those in preference to the default [Serializable] contract and allow you to explicitly indicate properties to serialize (and provide names clearer than the secret backing field names).
Unfortunately it is not always practical to add data contract attributes to legacy types.
NetDataContractSerializer has not been ported to .NET Core / .NET 5 and likely never will be.

How to ignore non-serializable properties from being cached using Akavache?

I have a custom class to be cached using Akavache. This class contains one non-serializable property (it's a ParseFile object). When I try to cache/get a list of this custom class using GetAndFetchLatest, it doesn't work. I figure it may be caused by one property that is non-serializable. Tried JsonIgnore attribute, but didn't help.
Question is, how can I tell Akavache to cache everything in the list of custom class, except the non-serializable property? Sample of the custom class is here, I want it to ignore the Photo property:
[ParseClassName("User")]
public class User : ParseObject
{
[ParseFieldName("name")]
public string Name
{
get { return GetProperty<string>(); }
set { SetProperty<string>(value); }
}
[ParseFieldName("photo")]
public ParseFile Photo
{
get { return GetProperty<ParseFile>(); }
set { SetProperty<ParseFile>(value); }
}
}
Use [DataContract] and [IgnoreDataMember] to prevent fields to be serialized
The default Json.Net behavior is to serialize all public fields and properties except those marked with the [JsonIgnoreAttribute] attribute.
ref: http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size

c# - DataContract Serialization - Base Classes, Inheritance and Overrides

Good day everyone,
I'm an independent game developer who has, in the past, primarily worked with XNA and, at the other extreme, commercial toolsets. The reach of XNA is pretty limited, however, and I'm building a cross-platform abstraction layer to target multiple platforms.
To cut a long story short, I've needed xml serialization that's accessible more broadly than [Serializable], and I've been pointed to data contracts. I've been doing a lot of research, but can't find any good information about some of the basics of the system, pertaining to inheritance and overrides.
The crux of my question is...
[DataContract]
public class Node
{
private string name;
public string Name { get { return name; } set { name = value; } }
public virtual float Rotation { get { return 0f; } set { } }
}
[DataContract]
public class FancyNode : Node
{
private float rotation;
public override float Rotation { get { return rotation; } set { rotation = value; } }
}
If I serialize a 'FancyNode', will 'Rotation' be properly serialized, and will 'Name' be serialised?
Follow-up Question:
I meant to ask earlier, but couldn't recall at the time. How does the serializer handler overriden [IgnoreDataMember] properties? For example...
[DataContract]
public class Simple
{
[IgnoreDataMember]
public virtual string Value { get { return ""; } set { } }
}
[DataContract]
public class Complex : Simple
{
private string value;
public override string Value { get { return value; } set { this.value = value; } }
}
Would 'Value' in 'Complex' be serialized? Some answers are suggesting that if no [DataMember] tags are used, all properties will be serialized. If so, does the [IgnoreDataMember] attribute of the base class have any bearing?
Some thoughts presented in a few answers are unclear. Please let me clear them up. First, the serializer that uses DataContract can be used to serialize types that are not decorated with DataContract. You only need to inform the serailizer about them.
For example, the DataContractJsonSerializer class will serialize a type into a JSON object (usually a string.) All you need to tell it is the type of object you're serializing, and then any other types it may reference:
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(MyClass), new Type[] { Type1, Type2, Type3 });
The serializer will automatically serialize each public field and property of the type. For more information, see http://msdn.microsoft.com/en-us/ms733127
DataContractAttribute Marked Types
Once you mark a type with the DataContractAttribute, you turn that type into an automatically known type (that you don't need to provide as a child type) and you turn it into the properties and fields into opt-in mode.
Therefore, you must decorate each field or property you want to be serialized with the DataMemberAttribute. This means that the IgnoreDataMemberAttribute is useless. It is, the serializer will not look for it, since anything not marked with the DataMemberAttribute is automatically ignored.
Unmarked DataContractAttribute Types
When serializing a type that does not have the DataContractAttribute applied, as previously stated, each public property or field will be serialized. Therefore, the IgnoreDataMemberAttribute is used here to prevent a property or field from being serialized.
As far as I know, DataContract is an 'opt-in' serialization method, i.e. stuff isn't serialized unless you decorate it (tell the serializer you want to serialize it)
So for the above example, you would need to add [DataMember] to the properties you wanted to serialize
With the standard Serializable attribute, the serializer looks at all fields and only ignores those which you mark as NonSerialized
Some examples here:
http://jamescbender.azurewebsites.net/?p=651
Check the notes section on this for info on what gets serialized and a rough outline of what happens:
http://msdn.microsoft.com/en-us/library/ms733127.aspx
Edit: Also I can't see any reason why any of the fields once marked as [DataMember] wouldn't be serialized properly. The DataContract method of serialization can also deal with circular references - something that other serialization sometimes has trouble with:
http://msdn.microsoft.com/en-us/library/hh241056.aspx
You should include the [DataMember] attribute on properties that should be exposed by the contract.
[DataContract]
public class FancyNode : Node
{
private float rotation;
[DataMember]
public override float Rotation { get { return rotation; } set { rotation = value; } }
}
Note that Windows Communication Foundation (WCF) uses the Data Contract Serializer to serialize and deserialize data (convert it to and from XML). So actually you are still using Xml Serialization.
No it wont serialize because of Opt-In approach, you have to explicitly apply DataMember to your base class. Data Serialization does not work automatically in case you Inherit in Child Class

.NET XmlIgnore By Default?

Is there a way to have XmlSerializer ignore all members by default, unless I say otherwise?
I have a base class and several derived classes with lots of members, but most I do not want to be serialized. Only a select few are acceptable for serialization.
No, you cannot do this.
The XmlSerializer is using a "opt-out" process - it will serialize everything (all public properties) unless you explicitly opt-out by using the [XmlIgnore] attribute. There's no way of changing this behavior.
The .NET 3.5 DataContractSerializer on the other hand is taking the other approach - opt-in. It will not serialize anything, unless you specifically tell it to, by decorating your members with [DataMember].
So maybe the DataContract serializer would work for you? It was a few more advantages (doesn't require a parameter-less constructor, can serialize internal and private properties, too, and it can also serialize fields instead of properties, if needed), and it's tuned for speed. There's some downsides, too - it doesn't support attributes in XML nodes - so you'll have to pick based on your requirements.
There's a good comparison of the two by Dan Rigsby - check it out!
Marc
You could implement IXMLSerializable and determine what you want to be serialized. Here is an example of Object serialization. Check out this SO post about the proper way to implement IXMLSerializable. Here is an example of IXMLSerializable using for some collections.
It would look something like this:
using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace ConsoleApplicationCSharp
{
public class ObjectToSerialize : IXmlSerializable
{
public string Value1;
public string Value2;
public string Value3;
public string ValueToSerialize;
public string Value4;
public string Value5;
public ObjectToSerialize() { }
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteElementString("Val", ValueToSerialize);
}
public void ReadXml(System.Xml.XmlReader reader)
{
if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "Event")
{
ValueToSerialize = reader["Val"];
reader.Read();
}
}
public XmlSchema GetSchema() { return (null); }
public static void Main(string[] args)
{
ObjectToSerialize t = new ObjectToSerialize();
t. ValueToSerialize= "Hello";
System.Xml.Serialization.XmlSerializer x = new XmlSerializer(typeof(ObjectToSerialize));
x.Serialize(Console.Out, t);
return;
}
}
}

Categories

Resources