I have the following class definitions:
public class Tag
{
public Guid? TagId { get; set; }
public string TagText { get; set; }
public DateTime C
Thanks to @Brian-Rogers's brilliant answer, I was able to come up with a non-generic solution which will work on all collections instead of List
only:
public class IgnoreEmptyArrayItemsConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
bool result = typeof(System.Collections.IEnumerable).IsAssignableFrom(objectType);
return result;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var tokenIndexesToRemove = new List<int>();
var array = JArray.Load(reader);
for (int i = 0; i < array.Count; i++)
{
var obj = array[i];
if (!obj.HasValues)
tokenIndexesToRemove.Add(i);
}
foreach (int index in tokenIndexesToRemove)
array.RemoveAt(index);
var result = array.ToObject(objectType, serializer);
return result;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Instead of looping through the objects, deserializing them and adding them to a hardcoded List
collection one by one, this solution will just remove the faulting tokens from the JArray
and let the library deserialize the whole array to the type it should be.
Usage:
public class Wiki
{
...
[JsonConverter(typeof(IgnoreEmptyItemsConverter))] // No generic parameter needed
public HashSet<Tag> Tags { get; set; }
}
Fiddle: https://dotnetfiddle.net/9FCcpD
You'll have to detect the empty tag objects post-conversion and remove them yourself. From the deserializer's perspective, {}
is a perfectly valid and complete Tag
object whose properties are all unset.
Something like the following should work (presuming C# 6):
Wiki wiki = JsonConvert.DeserializeObject<Wiki>(json);
wiki.Tags = Wiki.Tags?.Where(x => x.TagId.HasValue)?.ToList();
You could use a custom JsonConverter
to ignore the empty objects during deserialization. Something like this could work:
class IgnoreEmptyItemsConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsAssignableFrom(typeof(List<T>));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
List<T> list = new List<T>();
JArray array = JArray.Load(reader);
foreach (JObject obj in array.Children<JObject>())
{
if (obj.HasValues)
{
list.Add(obj.ToObject<T>(serializer));
}
}
return list;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use the converter, just add a [JsonConverter]
attribute to your Tags
property like this:
public class Wiki
{
...
[JsonConverter(typeof(IgnoreEmptyItemsConverter<Tag>))]
public IEnumerable<Tag> Tags { get; set; }
}
Fiddle: https://dotnetfiddle.net/hrAFsh