ArrayList
is a non-generic, untyped collection so you need to inform Json.NET of the expected type of the items. One way to do this is with a custom JsonConverter
for the ArrayList
:
public class ArrayListConverter<TItem> : JsonConverter
{
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var list = serializer.Deserialize<List<TItem>>(reader);
var arrayList = existingValue as ArrayList ?? new ArrayList(list.Count);
arrayList.AddRange(list);
return arrayList;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ArrayList);
}
}
Then apply the converter to the class as follows:
public class MyTestClass
{
[JsonConverter(typeof(ArrayListConverter<string []>))]
public ArrayList Items { get; private set; }
public MyTestClass()
{
this.Items = new ArrayList();
}
}
Sample fiddle.
If the class cannot be modified, and you want all instances of ArrayList
in your object graph to deserialize their items as string []
, you can add the converter to JsonSerializerSettings.Converters
instead of adding it to the type:
var tempMyObject = JsonConvert.DeserializeObject<MyTestClass>(jsonResult,
new JsonSerializerSettings { Converters = { new ArrayListConverter<string []>() } });
Sample fiddle #2.
And finally, if the class cannot be modified and you only want the specific ArrayList Items
property inside MyTestClass
to have its items deserialized as string []
, you will need to create a custom converter for MyTestClass
. You can use the pattern from Custom deserializer only for some fields with json.NET to custom-deserialize the ArrayList
property while populating the remainder with default deserialization:
public class MyTestClassConverter : JsonConverter
{
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var root = existingValue as MyTestClass ?? (MyTestClass)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
var jsonObject = JObject.Load(reader);
var jsonItems = jsonObject["Items"].RemoveFromLowestPossibleParent();
if (jsonItems != null && jsonItems.Type != JTokenType.Null)
{
root.Items.AddRange(jsonItems.ToObject<List<string []>>());
}
// Populate the remaining standard properties
using (var subReader = jsonObject.CreateReader())
{
serializer.Populate(subReader, root);
}
return root;
}
public override bool CanConvert(Type objectType)
{
return typeof(MyTestClass).IsAssignableFrom(objectType);
}
}
public static class JsonExtensions
{
public static JToken RemoveFromLowestPossibleParent(this JToken node)
{
if (node == null)
return null;
var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
if (contained != null)
contained.Remove();
// Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
if (node.Parent is JProperty)
((JProperty)node.Parent).Value = null;
return node;
}
}
Then use it as follows:
var tempMyObject = JsonConvert.DeserializeObject<MyTestClass>(jsonResult,
new JsonSerializerSettings { Converters = { new MyTestClassConverter() } });
Sample fiddle #3.