プロが教えるわが家の防犯対策術!

こん〇〇は
Windowsアプリについて
都道府県を選択すると天気を表示するというものです。

【構成】
FORMに
comboBox 1つ 東京・大阪・愛知・静岡のどれかを選択すると
Picturebox 1つ PICTUREBOXにその地方の天気(BMP形式)を表示

そのなかで、写真を取得するため?JSONというパッケージをつかってます。

【質問】

(string)((jobj["url"] as JValue).Value);のところで、Jobj型をJvalue型に変換できる
のでしょうか?

Jtoken,JObject、 JArray JValueというクラスがあるみたいで
Jtokenが親で派生がJobject(オブジェクト)
Jtokenが親で派生がJarray(配列)
Jtokenが親で派生がJValue(数値)

これらに共通の親 (継承元) が JToken となりJValueとJobjectはともに派生(親にはそれぞれつながっているけど、JavaleとJOBJECTは直接つながってない)
となっているので、AS (ダウンキャスト?)っていうのができないのではないかとおもうのですが、動いているので正しい記載だとおもうのですが、これがどうしてできるのでしょうか?

【参考】
https://netweblog.wordpress.com/2016/10/24/json- …

----------------------
それが以下のプログラムになります。
このサンプルプログラムは、c#超入門 p318となります。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Http;
using Newtonsoft.Json.Linq;

namespace WeatherChecker
{
public partial class Form1 : Form
{
Dictionary<string, string> cityNames;

public Form1()
{
InitializeComponent();

this.cityNames = new Dictionary<string, string>();

this.cityNames.Add("東京都", "3");
this.cityNames.Add("大阪府", "1");
this.cityNames.Add("愛知県", "2");
this.cityNames.Add("福岡県", "10");

foreach (KeyValuePair<string, string> data in this.cityNames)
{
areaBox.Items.Add(data.Key);
}
}

private void CitySelected(object sender, EventArgs e)
{
// 天気情報サービスにアクセスする
string cityCode = cityNames[areaBox.Text];
string url =
"http://and-idea.sbcr.jp/sp/90261/weatherCheck.ph … +
cityCode;
HttpClient client = new HttpClient();
string result = client.GetStringAsync(url).Result;

// 天気情報からアイコンのURLを取り出す
JObject jobj = JObject.Parse(result);
string todayweatherIcon = (string)((jobj["url"] as JValue).Value);
weatherIcon.ImageLocation = todayweatherIcon;
}
}
}

質問者からの補足コメント

  • うーん・・・

    naktak様
    以前 スーパークラス、サブクラスのサンプルでご説明いただいた件で
    (superCLASSの派生はSubclass)
    SuperClass super = new SuperClass();
    SubClass sub = new SubClass();
    SuperClass sub_super = new SubClass();
    SubClass subs = (SubClass)super; //エラー
    Superclass がJTOKENクラス、SUBCLASSがJvalueクラスたとえた場合
    SubClass subs = (SubClass)super に該当する?キャストできませんエラーがでる
    のにどうしてJTOKENからJVALUEへのキャストができるのでしょうか?

    No.3の回答に寄せられた補足コメントです。 補足日時:2019/03/11 21:19

A 回答 (6件)

No.4のお礼欄


> こんなイメージですか?
少し書き直してみました。

①jobj["url"](値)が「JValue型をアップキャストした」JToken型を返す。
 ※以下のコードはイメージです。
 public override JToken this[Object key]
 {
  get
  {
   JValue val = JValue型のオブジェクト;
   return (JToken)val; // JValue型をアップキャストする
  }
 }

②「JValue型をアップキャストした」Jtoken型は、Jvalue型にダウンキャストすることができる。


> ③ ①でえられたJtoken型の値はJvalue型を継承しているため、JVALUE型でJTOKEN型で得られた値を取得できる。

継承順が逆です、JValueがJTokenを継承しています。
https://www.newtonsoft.com/json/help/html/T_Newt …
> Inheritance Hierarchy
> System.Object
>  Newtonsoft.Json.Linq.JToken
>   Newtonsoft.Json.Linq.JValue

従って以下の様になります。

③ ①でえられたJtoken型の値は「JValue型をアップキャストしている」ため、
  JValue型にダウンキャストすることでJValue型として取り扱うことができる。
    • good
    • 0
この回答へのお礼

ありがとうございます。
過去に質問しご回答いただいた内容を読み返すと当時はあまり
気にならなかったことも有用なことが書かれていると再認識させられました。本当にありがとうございました。

お礼日時:2019/03/21 03:06

もう既に回答がありますが、元々がJObject, JArray, JValueのオブジェクトを、その上位クラスであるJTokenで受けているだけですね。


ですから、JValueのオブジェクトだった時、JObjectへキャストしようとしてもキャストできません。

以前の説明では、以下は行えます。
SuperClass sub_super = new SubClass();
var castObject = sub_super as SubClass;
    • good
    • 0

No.2です。



> Superclass がJTOKENクラス、SUBCLASSがJvalueクラスたとえた場合
> SubClass subs = (SubClass)super に該当する?キャストできませんエラーがでる
> のにどうしてJTOKENからJVALUEへのキャストができるのでしょうか?

もっと根本的な部分での疑問だったのですね。
これではNo.2の回答ではわかりませんよね、失礼しました。


JToken型オブジェクトがJValue型へダウンキャストできるのは、そのJToken型オブジェクトがJValue型をアップキャストしたものだからです。


jobj["url"]が返す値は扱うJSONデータの構成によって、本来はJObject型が適切だったり、JArray型が適切だったり、JValue型が適切だったりするわけです。
しかし、言語の仕様で返す型は一つにしかできないので、各々の型の基本クラスであるJToken型にアップキャストして返しているのです。


だから受け取った側は、JToken型オブジェクトが何をアップキャストしたものかを理解して処理する必要があります。



-----------------------------------
using System;
using Newtonsoft.Json.Linq;

class MyClass
{
static void Main(string[] args)
{
string json = @"
{
""results"": [
{
""id"": 1,
""name"": ""pc"",
""price"": 100000
},
{
""id"": 2,
""name"": ""mouse"",
""price"": 5000
},
{
""id"": 3,
""name"": ""phone"",
""price"": 30000
}
]
}
";

JObject obj = JObject.Parse(json);
JToken tkn = obj["results"]; // JToken型に代入
Console.WriteLine(tkn.GetType()); // tknの型:Newtonsoft.Json.Linq.JArray
Console.WriteLine(tkn.Type); // Typeプロパティ値:Array
}
}
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

>JToken型オブジェクトがJValue型へダウンキャストできるのは、そのJToken型オブジェ>クトがJValue型をアップキャストしたものだからです。
>jobj["url"]が返す値は扱うJSONデータの構成によって、本来はJObject型が適切だった>り、JArray型が適切だったり、JValue型が適切だったりするわけです。

こんなイメージですか?

①jobj["url"](値)がJToken型を返す(アップキャスト)
 public override JToken this[Object key] { get; set; }

②Jtoken型はJvalue型にダウンキャストすることができる。
 (上記ご回答いただいた内容より)

③ ①でえられたJtoken型の値はJvalue型を継承しているため、JVALUE型でJTOKEN型で得られた値を取得できる。

以上よろしくお願いいたします。

お礼日時:2019/03/15 01:42

jobjは型ではなく変数ですね。

(型はJObject)
そしてキャストしようとしているのはjobjではなくjobj["url"]であることから、そのキャスト前の型はJTokenになります。
https://www.newtonsoft.com/json/help/html/P_Newt …

そのため、キャストしようとしてるのはJTokenからJValueになります。
JValueはJTokenを継承元として持つため、キャスト可能です。
https://www.newtonsoft.com/json/help/html/T_Newt …

todayweatherIcon を得るための記述について順を追うと
1.JObject型の中にあるアイテム"url"のJTokenオブジェクトを取得。
2.JSON値のurlの値は、更なる下位構造があるわけではなくて、値が入っていることが
  分かりきっているので、JTokenをJValueに変換。
3.Value値をstringに変換。

Json.NETを学ぶつもりであるならば、それに焦点を当てて説明しているサイトのページや、
Json.NETのリファレンスを理解する必要があります。
https://www.newtonsoft.com/json/help/html/R_Proj …

しかし、教本を基準として読み進めているようですから、Json.NETの使い方は一旦おいておいてもいいのではないかと思います。
(恐らく教本としても、そこの記述がどういう仕組みでどうあるのかを重要視していない)
Json.NETは便利でいいのですが、規模が大きいので、継承やその他コードの記述に疎い状態の初回学習の入り口としては優しくありません。
この回答への補足あり
    • good
    • 0
この回答へのお礼

こん〇〇は
どうもありがとうございます。

この間、アップキャストとダウンキャストについておしえていただいたので、
この部分だけがわからずもやっとしてます。

>くjobj["url"]であることから、そのキャスト前の型はJTokenになります。
 
JObject型処理し戻り値としてJTOKEN型を返す。(マニュアルより)
型がJTOKEN型としてかえるので、Jvalueへキャスト可能なのでしょうか?

もしですよ、くjobj["url"]>がJTOKEN型でかえすのではなくJOBJECT型で返えるJVALUEには継承
できないんでしょうか?

>JValueはJTokenを継承元として持つため、キャスト可能です。

なぜ、JToken型だとJVALUEへキャストが可能なのでしょうか? 
ダウンキャストの基本的な話になるのでしょうか?
(わかっていること親がJTOKEN それに派生しているのがJvalue)

ここだけわかればあとはどうでもいいです。

宜しくお願いいたします。

お礼日時:2019/03/11 17:13

このライブラリについては、今回初めて知ったので推測になります。



> jobj["name"]が(中身)JToken型として
> 返されたものがJVALUE型に変換できるということがなぜわかるのでしょうか?

【参考】先の例では扱うJSONのデータがそのような構造になっているので決め打ちなのでしょう。
あくまでもサンプルなので。

実際に様々なデータを扱う場合はご指摘のとおり、
どのような構造になっているかわからないので、判別する手段が用意されているはずです。

その様な視点でJObjectのドキュメントを見ると以下の様なプロパティが用意されているのがわかります。

Object.Type Property
https://www.newtonsoft.com/json/help/html/P_Newt …
解説:Gets the node type for this JToken.


JTokenType Enumeration
https://www.newtonsoft.com/json/help/html/T_Newt …
解説:Specifies the type of token.


※ 要は新たに使用するもので、わからないところがあったらドキュメントを読めってことです。
    • good
    • 0

> (string)((jobj["url"] as JValue).Value);のところで、Jobj型をJvalue型に変換できるのでしょうか?



JValue型に変換されるのは、JObject型ではなくてjobj["url"]が返す何かです。


ドキュメントを見るとJToken型を返すようですね。
https://www.newtonsoft.com/json/help/html/P_Newt …



ご提示の【参考】先にも以下の様な説明があります。

> その配列の要素 1 つ 1 つは object なので JObject で受け取り (18 行目)、
> その中の値を JValue で受け取って (20, 22 行目)、

> 18:foreach (JObject jobj in jarr)
> 19:{
> 20: JValue nameValue = (JValue)jobj["name"];
> 21: string name = (string)nameValue.Value;

受け取ったJObjectの「中の値」をJValueに変換してますよね?
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

>ドキュメントを見るとJToken型を返すようですね。
 ありがとうございます。

>受け取ったJObjectの「中の値」をJValueに変換してますよね?
  はい。


jobj["name"]が(中身)JToken型として
返されたものがJVALUE型に変換できるということがなぜわかるのでしょうか?

わかっていること
JToken型は親 JVALUE型はそれに派生している
NAMEはJToken型のメンバー 

Jvalue型にするにはダウンキャストが必要である。 
Jvalue型のなかでJToken型のメンバーがつかえるってことですよね?
(そうだとしたらなんで使えるってわかるんですか?)
例)jvalue P= Jtokenクラス型 というイメージ

以上 よろしお願いいたします。

お礼日時:2019/03/10 05:53

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!