雑記 |
Visual Basic 中学校 > 雑記 >
2020/6/7
この記事が対象とする製品・バージョン
![]() |
Visual Studio 2019 | ◎ | 対象です。 |
![]() |
Visual Studio 2017 | ◎ | 対象です。 |
![]() |
Visual Studio 2015 | ◎ | 対象です。 |
![]() |
Visual Studio 2013 | ◎ | 対象ですが、サンプルの一部は動作しません。 |
![]() |
Visual Studio 2012 | ◎ | 対象ですが、サンプルの一部は動作しません。 |
![]() |
Visual Studio 2010 | ◎ | 対象ですが、サンプルの一部は動作しません。 |
![]() |
Visual Studio 2008 | ◎ | 対象ですが、サンプルの一部は動作しません。 |
![]() |
Visual Studio 2005 | ◎ | 対象ですが、サンプルの一部は動作しません。 |
![]() |
Visual Studio 2003 | × | 対象外です。 |
![]() |
Visual Studio (2002) | × | 対象外です。 |
目次
この記事では JSON.NET を扱います。
VB/C#でJSONを読み書きするには、JSON.NET(Newtonsoft JSON)またはSystem.Text.Jsonを使用するのが一般的です。
JSON.NETは非常に人気のあるライブラリで多機能です。あまりにもよくできていたためマイクロソフトのASP.NET CoreですらこのJSON.NETに依存する状況が発生してしまいました。後になってマイクロソフトはこの状況を脱却し、よりパフォーマンスの良い(その代わり機能の少ない)ライブラリを開発しました。それがSystem.Text.Jsonです。どちらを使っても通常の使用であれば機能・パフォーマンスともに申し分ありません。
この記事ではJSON.NETを扱います。
参考
↑この記事ではJSON.NETの基本的な考え方も説明しているので、少し複雑なことをやりたい場合は参考にしてください。
VB/C#でJSONの読み込み(System.Text.Json編)
JSON.NET(Newtonsoft JSON)は、プロジェクトの種類によってははじめから使えるようになっていますが、WindowsフォームアプリケーションなどではNuGetからインストールする必要があります。
NuGetからインストールする場合 Newtonsoft.Json で検索します。かなりメジャーなパッケージなので検索しなくてもはじめから一番上に表示されているかもしれません。
JSON.NETでJSONを生成する方法はいくつかあります。以下でいくつか紹介していきます。
JSONで表現したい内容をクラスで表現できるのであれば、JsonConvertクラスのSerializeObjectメソッドを使って簡単にJSONを生成できます。
既定ではPublicなプロパティ・フィールドが出力対象です。ただし既定では静的メンバー(定数、VBのShared、C#のstatic)は出力対象外です。
既定の設定はJsonProperty属性やJsonIgnore属性で簡単に変更できるほか、ContractResolverを使った上級者向けの設定も可能です。属性を使った例はこの後で示します。
JSONにシリアライズされるときにはクラス・プロパティ・フィールドの名前がそのまま使われます。これも変更する簡単な方法は属性を使うことです。クラスの場合JsonObject属性、プロパティ・フィールドの場合JsonProperty属性です。下記の例ではProductImageクラスと、ProductImageThumbnailクラスにJsonObject属性をつけてJSON化したときの名前を指定しています。
一番外側を表現するクラスだけは名前は出力されません。名前なしの { } になります。
なお、JSONの文字列が手元にある場合は、コピー&貼り付けを使って、 Visual Studioの編集メニューから[形式を選択して貼り付け] - [JSONをクラスとして貼り付ける]を選択すると、JSONをVB/C#のクラスに変換して貼り付けてくれるのでこの手のクラスを定義する際に便利です。ただし、思ったように変換してくれない部分を手で修正する必要がある場合もよくあります。
VB
Public
Class ProductInfo Public Property Image As ProductImage End Class <JsonObject("Image")> Public Class ProductImage Public Property OuterWidth As Integer Public Property OuterHeight As Integer Public Property Title As String Public Property Thumbnail As ProductImageThumbnail Public Property Animated As Boolean Public Property IDs As Integer() End Class <JsonObject("Thumbnail")> Public Class ProductImageThumbnail Public Property ImageUrl As String Public Property Height As Integer Public Property Width As Integer End Class Public Sub WriteJson() Dim productInfo As New ProductInfo Dim image As New ProductImage Dim thumbnail As New ProductImageThumbnail productInfo.Image = image image.OuterWidth = 800 image.OuterHeight = 600 image.Title = "15階からの眺望" image.Thumbnail = thumbnail thumbnail.ImageUrl = "http://www.example.com/image/481989943" thumbnail.Height = 125 thumbnail.Width = 100 image.Animated = False image.IDs = {116, 943, 234, 38793} Dim jsonText As String = JsonConvert.SerializeObject(productInfo, Formatting.Indented) Debug.WriteLine(jsonText) End Sub |
C#
public
class ProductInfo { public ProductImage Image { get; set; } } [JsonObject("Image")] public class ProductImage { public int OuterWidth { get; set; } public int OuterHeight { get; set; } public string Title { get; set; } public ProductImageThumbnail Thumbnail { get; set; } public bool Animated { get; set; } public int[] IDs { get; set; } } [JsonObject("Thumbnail")] public class ProductImageThumbnail { public string ImageUrl { get; set; } public int Height { get; set; } public int Width { get; set; } } public void WriteJson() { ProductInfo productInfo = new ProductInfo (); ProductImage image = new ProductImage (); ProductImageThumbnail thumbnail = new ProductImageThumbnail (); productInfo.Image = image; image.OuterWidth = 800; image.OuterHeight = 600; image.Title = "15階からの眺望"; image.Thumbnail = thumbnail; thumbnail.ImageUrl = "http://www.example.com/image/481989943"; thumbnail.Height = 125; thumbnail.Width = 100; image.Animated = false; image.IDs = new int[] { 116, 943, 234, 38793 }; string jsonText = JsonConvert.SerializeObject(productInfo, Formatting.Indented); System.Diagnostics.Debug.WriteLine(jsonText); } |
このプログラムのWriteJsonメソッドを実行すると出力ウィンドウには次のように出力されます。
{ "Image": { "OuterWidth": 800, "OuterHeight": 600, "Title": "15階からの眺望", "Thumbnail": { "ImageUrl": "http://www.example.com/image/481989943", "Height": 125, "Width": 100 }, "Animated": false, "IDs": [ 116, 943, 234, 38793 ] } } |
SerializeObjectの第2引数にFormatting.Indentedを指定しているのでこのように、インデント付きで改行されて出力されます。この引数を省略し、 JsonConvert.SerializeObject(productInfo) と記述すると、改行やインデントなしで次のように1行だけ出力されます。(ブラウザーの幅が十分広くない場合、表示上折り返されて2行、3行に見えるかもしれません。)
{"Image":{"OuterWidth":800,"OuterHeight":600,"Title":"15階からの眺望","Thumbnail":{"ImageUrl":"http://www.example.com/image/481989943","Height":125,"Width":100},"Animated":false,"IDs":[116,943,234,38793]}} |
上述したように 既定ではクラスで定義されている非静的なPublicなプロパティ・フィールドがJSONとして出力されます。基底クラスのプロパティ・フィールドも含みます。
プロパティ・フィールドにJsonIgnore属性をつけるとPublicなものでも出力されなくなります。
プロパティ・フィールドにJsonProperty属性をつけるとPublicでないものや静的なものでも出力されます。Constで宣言されているフィールドもJsonProperty属性をつけると出力されます。
VB
Public Class
JsonRoot Public Property PublicProp As String = "出力されます" <JsonProperty("ChangeName")> '←これがあると出力される名前が変わります。 Public Property NamedPublicProp As String = "名前が変わって出力されます" <JsonIgnore> '←これがあるとPublicプロパティでも出力されなくなります。 Public Property IgnoredPublicProp As String = "出力されません" Private Property PrivateProp As String = "出力されません" <JsonProperty> '←これがあるとPrivateプロパティでも出力されるようになります。 Private Property AttrPrivateProp As String = "出力されます" Public PublicField As String = "出力されます" Dim PrivateField As String = "出力されません" Public Const PublicConst As String = "出力されません" End Class Public Sub WriteJson() Dim productInfo As New JsonRoot Dim jsonText As String = JsonConvert.SerializeObject(productInfo, Formatting.Indented) Debug.WriteLine(jsonText) End Sub |
C#
public class
JsonRoot { public string PublicProp { get; set; } = "出力されます"; [JsonProperty("ChangeName")] //←これがあると出力される名前が変わります。 public string NamedPublicProp { get; set; } = "名前が変わって出力されます"; [JsonIgnore] //←これがあるとPublicプロパティでも出力されなくなります。 public string IgnoredPublicProp { get; set; } = "出力されません"; private string PrivateProp { get; set; } = "出力されません"; [JsonProperty] //←これがあるとPrivateプロパティでも出力されるようになります。 private string AttrPrivateProp { get; set; } = "出力されます"; public string PublicField { get; set; } = "出力されます"; string PrivateField = "出力されません"; public const string PublicConst = "出力されません"; } public void WriteJson() { JsonRoot productInfo = new JsonRoot(); string jsonText = JsonConvert.SerializeObject(productInfo, Formatting.Indented); System.Diagnostics.Debug.WriteLine(jsonText); } |
この例を実行すると出力ウィンドウには次のように出力されます。
{ "PublicField": "出力されます", "PublicProp": "出力されます", "ChangeName": "名前が変わって出力されます", "AttrPrivateProp": "出力されます" } |
既定の動作を変更して対象となるメンバーを指定するにはカスタムコンバーターを利用するか、DefaultContractResolverを継承してGetSerializableMembersメソッドとCreatePropertyメソッドをオーバーライドして使用します。
JSONのプロパティ名を書いて、オブジェクトを開始して、プロパティ名を書いて、値を書いて、オブジェクトを終了して・・・と逐一命令してJSONを生成することができます。
VB
Dim sb
As New System.Text.StringBuilder Using sw = New IO.StringWriter(sb) Using writer As New JsonTextWriter(sw) writer.Formatting = Formatting.Indented '改行とインデントをつけます。 writer.WriteStartObject() '{ writer.WritePropertyName("Team") ' "Team": writer.WriteStartObject() ' { writer.WritePropertyName("TeamName") ' "TeamName": writer.WriteValue("公安9課") ' "公安9課" writer.WritePropertyName("Authority") ' "Authority": writer.WriteValue("内務省") ' "内務省" writer.WritePropertyName("Leader") ' "Leader": writer.WriteStartObject() ' { writer.WritePropertyName("Name") ' "Name": writer.WriteValue("草薙素子") ' "草薙素子" writer.WriteEndObject() ' } writer.WritePropertyName("IDs") ' "IDs": writer.WriteStartArray() ' [ writer.WriteValue(123) ' 123, writer.WriteValue(456) ' 456 writer.WriteEndArray() ' ] writer.WriteEndObject() ' } writer.WriteEndObject() '} End Using End Using Dim jsonText As String = sb.ToString Debug.WriteLine(jsonText) |
C#
StringBuilder sb =
new
StringBuilder(); using (var sw = new System.IO.StringWriter(sb)) { using (var writer = new JsonTextWriter(sw)) { writer.Formatting = Formatting.Indented; //改行とインデントをつけます。 writer.WriteStartObject(); //{ writer.WritePropertyName("Team"); // "Team": writer.WriteStartObject(); // { writer.WritePropertyName("TeamName"); // "TeamName": writer.WriteValue("公安9課"); // "公安9課" writer.WritePropertyName("Authority"); // "Authority": writer.WriteValue("内務省"); // "内務省" writer.WritePropertyName("Leader"); // "Leader": writer.WriteStartObject(); // { writer.WritePropertyName("Name"); // "Name": writer.WriteValue("草薙素子"); // "草薙素子" writer.WriteEndObject(); // } writer.WritePropertyName("IDs"); // "IDs": writer.WriteStartArray(); // [ writer.WriteValue(123); // 123, writer.WriteValue(456); // 456 writer.WriteEndArray(); // ] writer.WriteEndObject(); // } writer.WriteEndObject(); //} } } string jsonText = sb.ToString(); System.Diagnostics.Debug.WriteLine(jsonText); |
この例を実行すると出力ウィンドウには次のように出力されます。
{ "Team": { "TeamName": "公安9課", "Authority": "内務省", "Leader": { "Name": "草薙素子" }, "IDs": [ 123, 456 ] } } |
逐一命令するのであれば文字列を直接生成しても同じように思うかもしれませんが、JSON.NETを使って書き込むことで、他の便利なJSON.NETの機能と連携できます。
たとえば、この例ではJsonTextWriterクラスのFormattingプロパティを使って改行とインデントをつけるようにしています。この行をコメントにするだけで、改行されずにすべて1行で出力されます。
他にもJsonTextWriterクラスは便利な機能を持っています。QuoteNameプロパティをFalseにセットして、プロパティ名に " をつけないようにしたり、DateFormatStringプロパティを使って、日付をJSON化するときの書式を一律で指定したり、StringEscapeHandlingプロパティを使って日本語をUnicodeエンコードしたりなどが簡単にできます。自分で文字列でJSONを生成している場合は、このようなちょっとした変更が簡単にはできません。
Dictionaryはキーと値を保存する構造であり、ほとんどのJSONと同じです。
JSON.NETはDictionaryをもとにして簡単にJSONを生成することができます。Dictionaryの項目の値をDictionaryにすることで入れ子の構造も表現できます。
VB
Dim productInfo
As New
Dictionary(Of String,
Object) Dim image As New Dictionary(Of String, Object) Dim thumbnail As New Dictionary(Of String, Object) productInfo.Add("Image", image) image.Add("Width", 800) image.Add("Height", 600) image.Add("Title", "15階からの眺望") image.Add("Thumbnail", thumbnail) thumbnail.Add("Url", "http://www.example.com/image/481989943") thumbnail.Add("Height", 125) thumbnail.Add("Width", 100) image.Add("Animated", False) image.Add("IDs", {116, 943, 234, 38793}) Dim jsonText As String = JsonConvert.SerializeObject(productInfo, Formatting.Indented) Debug.WriteLine(jsonText) |
C#
var productInfo =
new Dictionary<string,
object>(); var image = new Dictionary<string, object>(); var thumbnail = new Dictionary<string, object>(); productInfo.Add("Image", image); image.Add("Width", 800); image.Add("Height", 600); image.Add("Title", "15階からの眺望"); image.Add("Thumbnail", thumbnail); thumbnail.Add("Url", "http://www.example.com/image/481989943"); thumbnail.Add("Height", 125); thumbnail.Add("Width", 100); image.Add("Animated", false); image.Add("IDs", new int[] { 116, 943, 234, 38793 }); string jsonText = JsonConvert.SerializeObject(productInfo, Formatting.Indented); System.Diagnostics.Debug.WriteLine(jsonText); |
この例を実行すると出力ウィンドウには次のように出力されます。
{ "Image": { "Width": 800, "Height": 600, "Title": "15階からの眺望", "Thumbnail": { "Url": "http://www.example.com/image/481989943", "Height": 125, "Width": 100 }, "Animated": false, "IDs": [ 116, 943, 234, 38793 ] } } |
Dictionaryを使ってJSONを生成する方法と同じようなものですが、Dictionaryの内容をコレクション初期化子を活用して記述することで、プログラムの雰囲気は全然違うものなります。
VB
Dim jsonText
As String =
JsonConvert.SerializeObject(New
Dictionary(Of
String, Object)
From { {"Image", New Dictionary(Of String, Object) From { {"Width", 800}, {"Height", 600}, {"Title", "15階からの眺望"}, {"Thumbnail", New Dictionary(Of String, Object) From { {"Url", "http://www.example.com/image/481989943"}, {"Height", 125}, {"Width", 100}}}, {"Animated", False}, {"IDs", {116, 943, 234, 38793}}}}}, Formatting.Indented) Debug.WriteLine(jsonText) |
C#
string jsonText =
JsonConvert.SerializeObject(new
Dictionary<string,
object> { {"Image", new Dictionary<string, object> { {"Width", 800}, {"Height", 600}, {"Title", "15階からの眺望"}, {"Thumbnail", new Dictionary<string, object> { {"Url", "http://www.example.com/image/481989943"}, {"Height", 125}, {"Width", 100}}}, {"Animated", false}, {"IDs", new int[]{ 116, 943, 234, 38793}}}}}, Formatting.Indented); System.Diagnostics.Debug.WriteLine(jsonText); |
この例を実行すると出力ウィンドウには他の例と同じ次の内容が出力されます。
{ "Image": { "Width": 800, "Height": 600, "Title": "15階からの眺望", "Thumbnail": { "Url": "http://www.example.com/image/481989943", "Height": 125, "Width": 100 }, "Animated": false, "IDs": [ 116, 943, 234, 38793 ] } } |
これも Dictionaryを使ってJSONを生成する方法やコレクション初期化子を使う方法と同じようなものですが、こういう書き方もできるという例を紹介しておきます。
VB
Dim productInfo =
New With { .Image = New With { .OuterWidth = 800, .OuterHeight = 600, .Title = "15階からの眺望", .Thumbnail = New With { .ImageUrl = "http://www.example.com/image/481989943", .Height = 125, .Width = 100 }, .Animated = False, .IDs = {116, 943, 234, 38793} } } Dim jsonText As String = JsonConvert.SerializeObject(productInfo, Formatting.Indented) Debug.WriteLine(jsonText) |
C#
var productInfo =
new { Image = new { OuterWidth = 800, OuterHeight = 600, Title = "15階からの眺望", Thumbnail = new { ImageUrl = "http://www.example.com/image/481989943", Height = 125, Width = 100 }, Animated = false, IDs = new int[] { 116, 943, 234, 38793 } } }; string jsonText = JsonConvert.SerializeObject(productInfo, Formatting.Indented); System.Diagnostics.Debug.WriteLine(jsonText); |
この例を実行すると出力ウィンドウには他の例と同じ次の内容が出力されます。
{ "Image": { "Width": 800, "Height": 600, "Title": "15階からの眺望", "Thumbnail": { "Url": "http://www.example.com/image/481989943", "Height": 125, "Width": 100 }, "Animated": false, "IDs": [ 116, 943, 234, 38793 ] } } |
参考
.NET での JSON のシリアル化と逆シリアル化 (マーシャリングとアンマーシャリング)-概要
https://docs.microsoft.com/ja-jp/dotnet/standard/serialization/system-text-json-overview
Newtonsoft. Json から system.string に移行する方法
Try the new System.Text.Json APIs
https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/