Dictionary<TKey, TValue> クラスのオブジェクトを、ASP.NET MVC の Controller クラスの Json メソッドなどで使われている JavaScriptSerializer クラスを用いて JSON 文字列にシリアライズするとどうなるかという話を書きます。
例えば、以下のような Controller のアクションメソッドで Dictionary<string, Car> オブジェクトを作って Json メソッドで JSON 文字列にシリアライズしてみます。(注: TKey は JSON の「名前:値」ペアの「名前」になるので string 型にする必要があるようです。実際 int 型ではエラーになりました)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Mvc5App.Controllers
{
public class Car
{
public string Make { get; set; }
public string Model { get; set; }
public int Year { get; set; }
public float Price { get; set; }
}
public class HomeController : Controller
{
public ActionResult JsonDictionary()
{
Dictionary<string, Car> dic =
new Dictionary<string, Car>()
{
{ "Car1", new Car() { Make="Audi",
Model="A4", Year=1995, Price=2995f } },
{ "Car2", new Car() { Make="Ford",
Model="Focus", Year=2002, Price=3250f } },
{ "Car3", new Car() {Make="BMW",
Model ="503i",Year=1997,Price=1995f } }
};
return Json(dic);
}
}
}
上のアクションメソッドをブラウザから POST 要求すると、以下の JSON 文字列が応答として返ってきます。(注: POST 要求するのは、Json メソッドはデフォルトでは GET 要求を拒否するからです)
{
"Car1":{"Make":"Audi","Model":"A4","Year":1995,"Price":2995},
"Car2":{"Make":"Ford","Model":"Focus","Year":2002,"Price":3250},
"Car3":{"Make":"BMW","Model":"503i","Year":1997,"Price":1995}
}
つまり、JSON の「名前:値」ペアとして、Dictionary<TKey, TValue> の TKey が「名前」に、 TValue(Car の JavaScript オブジェクトの JSON 文字列) が「値」に設定され、そのペアが Dictionary の要素の数(上の例では 3 つ)並べられた JSON 文字列になります。
知ってました? 実は自分は知らなかったです。(汗) Dictionary<TKey, TValue> なんて JSON にシリアライズできないと思ってました。(恥)
デシリアライズも、もちろんできるようです。例えば、jQuery alax を利用して上記アクションメソッドを呼び出すと、自動的に JSON 文字列が JavaScript オブジェクトにデシリアライズされ、コールバックの引数として渡されます。
以下の例を見てください、function(data) ... の引数 data にデシリアライズされた JavaScript オブジェクトが渡されます。それを jsonresult という id を持つ div 要素の中に書き込んだのが上の画像です。
function jsonDictionary() {
$.ajax({
type: 'POST',
url: '/home/jsonDictionary'
})
.done(function (data) {
$("#jsonresult").empty();
$.each(data, function (index, car) {
$('#jsonresult').append(
'<p><strong>' + index + '</strong></p>' +
'<p>' + car.Make + ' ' + car.Model +
', Year: ' + car.Year +
', Price: $' + car.Price + '</p>');
});
})
.fail(function (jqXHR, textStatus, errorThrown) {
$("#jsonresult").text('textStatus: ' + textStatus +
', errorThrown: ' + errorThrown);
})
}
上のコードの例では、jQuery の jQuery.each() メソッドを使っていますが、JavaScript の for ... in ループを使って同じ処置を行う例も書いておきます。
for (var key in data) {
$('#jsonresult').append(
'<p><strong>' + key + '</strong></p>' +
'<p>' + data[key].Make + ' ' + data[key].Model +
', Year: ' + data[key].Year +
', Price: $' + data[key].Price + '</p>');
}
元の .NET Framework の Dictionary<string, Car> オブジェクトにも JavaScriptSerializer や Json.NET (Newtonsoft.Json) を使ってデシリアライズできます。
string json = "上の JSON 文字列";
// JavaScriptSerializer
JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, Car> dic =
serializer.Deserialize<Dictionary<string, Car>>(json);
// Json.NET (Newtonsoft.Json)
Dictionary<string, Car> dic =
JsonConvert.DeserializeObject<Dictionary<string, Car>>(json);
ただし、DataContractJsonSerializer では、自分が試した限りですが、ダメでした。何かやり方はあるのかもしれませんが。