I'm attempting to serialize an object array, but I need it to ignore null elements. I realize I could simply have logic upon deserialization that checks for the nulls, however I don't want to write unnecessary data over the network. The array can have a maximum of 9 elements, but all 9 indices are not used in every instance. I understand that a list could be utilized, but for efficiency sake I do not wish to do that.
Per similar questions I've browsed on this site, I've attempted to add the following tag to the array: [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
However, this approach does not ignore null elements.
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Node[] Nodes { get; }
public void Init()
{
Nodes = new Node[9];
}
public string Encode()
{
return JsonConvert.SerializeObject(Nodes, Formatting.None);
}
Is there an elegant solution to this?
The simplest solution is just to filter the array just before you serialize it. You can do this in your Encode method, without instantiating a new array:
public string Encode()
{
return JsonConvert.SerializeObject(Nodes.Where(n => n != null), Formatting.None);
}
Fiddle: https://dotnetfiddle.net/dj8lnP
If you don't like that idea, for whatever reason, you can use a custom JsonConverter similar to the one in Excluding specific items in a collection when serializing to JSON to do the filtering.
Related
Some custom types that implement IEnumerable don't necessarily have backing collections. They could be generated dynamically, for example using 'yield' or LINQ. Here is an example:
public class SOJsonExample
{
public class MyCustomEnumerable : IEnumerable<KeyValuePair<int,float>>
{
public List<int> Keys { get; set; } = new List<int> { 1, 2, 3 };
public List<float> Values { get; set; } = new List<float> { 0.1f, 0.2f, 0.3f };
public IEnumerator<KeyValuePair<int, float>> GetEnumerator()
{
var kvps =
from key in Keys
from value in Values
select new KeyValuePair<int, float>(key, value);
return kvps.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}
}
I have discovered that the default serialization by Json.NET is to enumerate each value and store the values in a JavaScript array (which I don't want). The default deserializer will then fail to deserialize the collection as it can't be populated. In these cases, I'd instead want Json.NET to skip the default JavaScript array serialization, and just store the members of the class.
All I want is my keys and values - is there any shortcut way to do this, or do I have to implement my own custom serializer?
Checked this and this, neither of which are exactly my question. Scanned the documentation as well, but didn't find what I was looking for (perhaps I looked in the wrong place).
(Edit #1 - improved clarity)
(Edit #2 - answered my own question...see below)
(Edit #3 - updated to more modern C#)
Answered my own question - see the excellent documentation on IEnumerable, Lists, and Arrays:
.NET lists (types that inherit from IEnumerable) and .NET arrays are converted to JSON arrays. Because JSON arrays only support a range of values and not properties, any additional properties and fields declared on .NET collections are not serialized. In situations where a JSON array is not wanted the JsonObjectAttribute can be placed on a .NET type that implements IEnumerable to force the type to be serialized as a JSON object instead.
So, for my example:
[JsonObject]
public class MyCustomEnumerable : IEnumerable<KeyValuePair<int,float>>
{
...
}
I have a class which I use the XmlSerializer with to serialize data to and from XML files.
I have several DateTime properties. In the post, Prevent timezone conversion on deserialization of DateTime value the answer correctly removes timezone offsets from DateTime properties.
However, I have a property which is a list of DateTime objects that I can't remove the timezones from.
[XmlElement]
public List<DateTime> Times {get; set;}
I have tired something like this, but the value is always null and none of the data is correctly serialized to the list property.
[XmlIgnore]
public List<DateTime> Times {get; set;}
[XmlElement(ElementName = "Times")]
public List<string> TimesString
{
get
{
return Times.ForEach(fe => RemoveTimeZone(fe));
}
set
{
foreach(var v in value)
{
Times.Add(ConvertToDate(v));
}
}
}
The value property is always empty and both list properties are always empty.
My goal is to not create a new class, but to somehow bind directly to my list properties.
Your TimesString property is a proxy collection property, i.e. a property that gets or sets an underlying collection, transforming its members in the process. The simplest way to make such a proxy collection work correctly with XmlSerializer is to make it be an array rather than a list, in your case a string []:
[XmlIgnore]
public List<DateTime> Times { get; set; }
[XmlElement(ElementName = "Times")]
public string [] TimesString
{
get
{
return Times == null ? null : Times.Select(t => RemoveTimeZone(t)).ToArray();
}
set
{
if (value == null)
return;
(Times = Times ?? new List<DateTime>(value.Length)).AddRange(value.Select(s => ConvertToDate(s)));
}
}
string [] works while List<string> does not because XmlSerializer deserializes a property referring to a class implementing IList<T> in the following way:
It calls the getter to get the list. If null, it allocates a list and sets it via the setter. It holds onto the list in some local variable while populating it.
It deserializes each list element, and adds it to the list it is holding.
And that's it. It never calls the containing class's list property setter afterwards.
However, since an array is basically a read-only collection and so cannot be added to once allocated, it cannot be set back until completely populated. This is what XmlSerializer does, which allows proxy array properties to deserialized successfully.
For more, see Cannot deserialize XML into a list using XML Deserializer or XML Deserialization of collection property with code defaults.
I have a property
[XmlElement]
public string[] Emails { get; set; }
which is initialized as string[0] at constructor.
If I XML serialize and deserialize a default instance of this object, the property is NULL.
How can I tell the XML Serializer to use an empty array instead of NULL for this property?
5 years later... :)
Replacing Array with List<> did the trick for me.
[XmlElement (IsNullable = false)]
public List<string> Emails {get;set;}
I want to serialize a MyClass, which is a class that contains a list MyClass.
In the XML, I want to write only myClass.Name, then when I deserialize it, I then find which MyClass should be in which other MyClass. I have the following code that properly serializes the list of MyClass into a list of string. However, it doesn't deserialize the list of string.
//List of actual object. It's what I use when I work with the object.
[XmlIgnore]
public List<TaskConfiguration> ChildTasks { get; set; }
//Used by the serializer to get the string list, and used
//by the serializer to deserialize the string list to.
[XmlArray("ChildTasks")]
public List<string> ChildTasksSurrogate
{
get
{
List<string> childTaskList = new List<string>();
if (ChildTasks != null)
childTaskList.AddRange(ChildTasks.Select(ct => ct.Name).ToList());
if (_childTasksSurrogate != null)
childTaskList.AddRange(_childTasksSurrogate);
//Clears it not to use it when it serializes.
_childTasksSurrogate = null;
return childTaskList;
}
set
{
_childTasksSurrogate = value;
}
}
[XmlIgnore]
private List<string> _childTasksSurrogate;
As I said, the serialization works. The problem lies with the deserialization. After the deserialization, MyClass._childTasksSurrogate is null.
The problem was related to HOW does the XmlSerializer deserializes the Xml :
I thought that the XmlSerializer would assign the whole property (read: myList = DeserializedList), while it looks like it adds all the elements (read: myList.AddRange(DeserializedList).
I have a JSON-string with a fixed number of arrays of different objects (created in Java with JSONObjects and JSONArrays):
[
[ //The first type of object
{
"Initials":"MUS"
},
{
"Initials":"NA"
}
],
[ //The second type
{
"ToolId":17
},
{
...
}
]
... //etc.
]
So I've created some Dummy-classes that has corresponding properties to the objects within the array, which works:
private class DummyEmployee
{
public string Initials { get; set; }
}
//etc.
But I can't figure out how the container class should be designed. This is how I did it:
private class DataContainer
{
public List<DummyEmployee> Employees { get; set; }
public List<DummySecondType> SecondTypes { get; set; }
//etc.
}
This is how I attempt to deserialize the JSON-data:
JavaScriptSerializer ser = new JavaScriptSerializer();
string jsonDataFromClient = ...;
DataContainer jsonData = ser.Deserialize<DataContainer>(jsonDataFromClient);
And it doesn't work. I get the following error while passing the data:
Type 'GUI.ValidateLoginData+DataContainer' is not supported for deserialization of an array.
I couldn't find any other subjects on the matter of deserializing arrays of different objects.
yes i will not work
notice that in your javascript object is basically an array and because javascript is a dynamic language there it is a valid array where as c# isnt so an array(or list) must contain objects of same kind. however if you still need to implement this and you have control over your JSON structure edit it to this
{
Employees:[ //The first type of object
{
"Initials":"MUS"
},
{
"Initials":"NA"
}
],
SecondTypes:[ //The second type
{
"ToolId":17
},
{
...
}
]
... //etc.
}
and your current c# object might map correctly.
and if you dont have control over the JSON structure then you have to use dynamic objects in c#
UPDATE:-for the case in which you dont have control over your JSON structure (or you dont wanna edit it).
try deserializing your JSON object to an array of dynamic type
UPDATE 2:- because you are curious try deserializing the existing JSON structure to an object of type List<List<dynamic>> and though i havent tried it but it should work fine.
one disadvantage of this solution however is that you wont be able to distinguish between two different types of objects namely Employee and SecondTypes
Use this online tool to create the C# classes for you. You can then fine tune the classes (Name, etc) as per you need. At least, you can get idea that the model classes that you are creating are correct or not.
JSON to C#
did you add [Serializable] attribute to your DataContainer?