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:
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.NullValueHandling.Ignore
is not working because the propertyEntity.Number
is not null, it has a value, namely an allocatedHasValue<int?>
struct with anull
inner value:Number = new HasValue<int?>(number) // Not Number = null
Similarly
DefaultValueHandling.Ignore
is not working becausedefault(HasValue<int?>?)
has the same value as a null nullable value -- which, as mentioned above, differs from the value assigned toNumber
.
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 Object
s); 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 string
s 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
Inheritance with Base Class Constructor with Parameters
Why Isn't Arraylist Marked [Obsolete]
Passing Object in Redirecttoaction
Arbitrary-Precision Decimals in C#
Model-View-Presenter in Winforms
How to Initialize a List of Strings (List<String>) with Many String Values
Save and Retrieve Image (Binary) from SQL Server Using Entity Framework 6
How to Access Configuration in Any Class in ASP.NET Core
How to Find Out If a File Exists in C#/.Net
How to Convert PDF Files to Images
Multiple Colors in a C# .Net Label
Wpf C# Path: How to Get from a String with Path Data to Geometry in Code (Not in Xaml)
Why Can't I Access C# Protected Members Except Like This
Should You Implement Idisposable.Dispose() So That It Never Throws