Serialize a Nullable Int

Serialize a nullable int

XmlSerializer supports the ShouldSerialize{Foo}() pattern, so you can add a method:

public bool ShouldSerializeID() {return ID.HasValue;}

There is also the {Foo}Specified pattern - not sure if XmlSerializer supports that one.

How to Serialize using JSON.NET and Ignore a Nullable Struct Value

You have three problems here:

  1. As explained in this answer to Custom Json.NET converter should not serialize a property:

    A custom JsonConverter cannot prevent its value from being serialized, because the property name referring to it will already have been written out by the time the converter is invoked. In Json.NET's architecture it is the responsibility of the containing type to decide which of its properties to serialize; the value converter then decides how to serialize the value being written.

  2. NullValueHandling.Ignore is not working because the property Entity.Number is not null, it has a value, namely an allocated HasValue<int?> struct with a null inner value:

    Number = new HasValue<int?>(number) // Not Number = null
  3. Similarly DefaultValueHandling.Ignore is not working because default(HasValue<int?>?) has the same value as a null nullable value -- which, as mentioned above, differs from the value assigned to Number.

So what are your options here?

You could use conditional property serialization to suppress serialization of Number when it's value is a non-null but with a null inner value:

public class Entity
{
[JsonConverter(typeof(NullJsonConverter))]
public HasValue<int?>? Number { get; set; }

public bool ShouldSerializeNumber() { return Number.HasValue && Number.Value.Value.HasValue; }
}

Demo fiddle #1 here.

However, this design seems a little overcomplex -- you have a nullable containing a struct that encapsulates nullable containing an integer -- i.e. Nullable<HasValue<Nullable<int>>>. Do you really need both levels of nullable? If not, you could simply remove the outer Nullable<> and DefaultValueHandling will now just work:

public class Entity
{
[JsonConverter(typeof(NullJsonConverter))]
public HasValue<int?> Number { get; set; }
}

Demo fiddle #2 here.

In both cases I generalized NullJsonConverter to handle all possible types T for HasValue<T> as follows:

public struct HasValue<T> : IHasValue
{
// Had to convert to c# 4.0 syntax for dotnetfiddle
T m_value;
public HasValue(T value) { this.m_value = value; }
public T Value { get { return m_value; } set { m_value = value; } }

public object GetValue() { return Value; }
}

internal interface IHasValue
{
object GetValue();
}

public class NullJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) { throw new NotImplementedException(); }

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var valueType = objectType.GetGenericArguments()[0];
var valueValue = serializer.Deserialize(reader, valueType);
return Activator.CreateInstance(objectType, valueValue);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, ((IHasValue)value).GetValue());
}
}

Specifically by:

  • Changing the Value property to be typed.
  • Adding a non-generic interface to access the value as an object during serialization.
  • Directly deserializing the inner value then invoking the parameterized constructor during deserialization.

Thus you could apply [JsonConverter(typeof(NullJsonConverter))] to HasValue<T> itself if you prefer.

You might also consider making your HasValue<T> struct be immutable for reasons explained in Why are mutable structs “evil”?.

What is the correct way to serialize nullable types?

You want to always write the XML for the property, but if the property value is null you want to include an xsi:nil="true" attribute.

void IXmlSerializable.WriteXml(XmlWriter writer)
{
...

if (this._PropName == null)
{
writer.WriteStartElement("PropName");
writer.WriteAttributeString("xsi", "nil", "http://www.w3.org/2001/XMLSchema-instance", "true");
writer.WriteEndElement();
}
else
{
writer.WriteElementString("PropName", this._PropName.ToString());
}
...
}

You are also probably going to want to write an xsi:type="xsd:datatype" attribute, where xsd is the http://www.w3.org/2001/XMLSchema namespace. This will allow you to read the data type back in during deserialization to know if (and how) to convert the value.

How to make a value type nullable with .NET XmlSerializer?

I just discovered this. XmlSerialier looks for a XXXSpecified boolean property to determine if it should be included. This should solve the problem nicely.

[Serializable]
public class MyClass
{
public int Age { get; set; }
[XmlIgnore]
public bool AgeSpecified { get { return Age >= 0; } }
public int MyClassB { get; set; }
}

[Serializable]
public class MyClassB
{
public int RandomNumber { get; set; }
}

Proof:

static string Serialize<T>(T obj)
{
var serializer = new XmlSerializer(typeof(T));
var builder = new StringBuilder();
using (var writer = new StringWriter(builder))
{
serializer.Serialize(writer, obj);
return builder.ToString();
}
}

static void Main(string[] args)
{
var withoutAge = new MyClass() { Age = -1 };
var withAge = new MyClass() { Age = 20 };

Serialize(withoutAge); // = <MyClass><MyClassB>0</MyClassB></MyClass>
Serialize(withAge); // = <MyClass><Age>20</Age><MyClassB>0</MyClassB></MyClass>
}

Edit: Yes, it is a documented feature. See the MSDN entry for XmlSerializer

Another option is to use a special pattern to create a Boolean field recognized by the XmlSerializer, and to apply the XmlIgnoreAttribute to the field. The pattern is created in the form of propertyNameSpecified. For example, if there is a field named "MyFirstName" you would also create a field named "MyFirstNameSpecified" that instructs the XmlSerializer whether to generate the XML element named "MyFirstName".

Json.NET, Unable to de-serialize nullable type

The error is telling you that it cant find a a constructor that it can use for the deserialization.

Try adding a default constructor to the class:

public class MyObject
{
public int? integerValue { get; set; }
public DateTime? dateTimeValue { get; set; }

public MyObject(){}
}

Patrick.

--EDIT--

So I've just created a simple console app using your MyObject, with and without a default constructor and I'm getting no errors. Here is my example:

class Program
{
static void Main(string[] args)
{
var mo = new MyObject { integerValue = null, dateTimeValue = null };
var ser = Newtonsoft.Json.JsonConvert.SerializeObject(mo);
var deser = Newtonsoft.Json.JsonConvert.DeserializeObject(ser, typeof(MyObject));
}
}

public class MyObject
{
public int? integerValue { get; set; }
public DateTime? dateTimeValue { get; set; }
}

I get no exceptions...

Can you show an example of the JSON that you are trying to deserialize?

Deserializing empty xml attribute value into nullable int property using XmlSerializer

I solved this problem by implementing IXmlSerializable interface. I did not found easier way.

Here is the test code sample:

[XmlRoot("root")]
public class DeserializeMe {
[XmlArray("elements"), XmlArrayItem("element")]
public List<Element> Element { get; set; }
}

public class Element : IXmlSerializable {
public int? Value1 { get; private set; }
public float? Value2 { get; private set; }

public void ReadXml(XmlReader reader) {
string attr1 = reader.GetAttribute("attr");
string attr2 = reader.GetAttribute("attr2");
reader.Read();

Value1 = ConvertToNullable<int>(attr1);
Value2 = ConvertToNullable<float>(attr2);
}

private static T? ConvertToNullable<T>(string inputValue) where T : struct {
if ( string.IsNullOrEmpty(inputValue) || inputValue.Trim().Length == 0 ) {
return null;
}

try {
TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
return (T)conv.ConvertFrom(inputValue);
}
catch ( NotSupportedException ) {
// The conversion cannot be performed
return null;
}
}

public XmlSchema GetSchema() { return null; }
public void WriteXml(XmlWriter writer) { throw new NotImplementedException(); }
}

class TestProgram {
public static void Main(string[] args) {
string xml = @"<root><elements><element attr='11' attr2='11.3'/><element attr='' attr2=''/></elements></root>";
XmlSerializer deserializer = new XmlSerializer(typeof(DeserializeMe));
Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml));
var result = (DeserializeMe)deserializer.Deserialize(xmlStream);
}
}

Generating IL for NullableT serialization?

Explicit and implicit conversions are a purely C# concept.

IL does not have any special awareness of nullable types (except for boxing them into Objects); you need to explicitly use .Value or call the ctor.

For examples, look at the IL generated by the C# compiler.

How to deserialize json array with nulls to non-nullable int list with JSON.NET?

Since you are using Json.NET, you can build a custom converter to handle empty strings and convert them to int. Here's a start:

public class NullableStringToIntConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => typeof(List<string>) == objectType;

public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
var items = serializer.Deserialize<List<string>>(reader);

return items
.Where(s => !string.IsNullOrEmpty(s))
.Select(int.Parse)
.ToList();

throw new NotImplementedException();
}

public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

And your class to deserialise into would look something like this:

public class Thing
{
[JsonConverter(typeof(NullableStringToIntConverter))]
public List<int> Edges { get; set; }
}

And finally to deserialise:

var thing = JsonConvert.DeserializeObject<Thing>(json);

An integer set to 0 is serialized(using protobuf-net) as null. Any workarounds to fix this problem?

By default, protobuf-net follows proto3 conventions of zero===default===not-serialized, but you can override this behaviour by using IsRequired on the ProtoMemberAttribute:

[ProtoMember(42, IsRequired = true)]
public int Foo {get;set;}

Alternatively, in more advanced scenarios, you can use "conditional serialization" (this same approach works with a wide range of serializers):

[ProtoMember(42)]
public int Foo {get;set;}

public bool ShouldSerializeFoo() { /* your own rules here */ }


Related Topics



Leave a reply



Submit