72

これが私の簡単なUserPOCOクラスです。

/// <summary>
/// The User class represents a Coderwall User.
/// </summary>
public class User
{
    /// <summary>
    /// A User's username. eg: "sergiotapia, mrkibbles, matumbo"
    /// </summary>
    public string Username { get; set; }

    /// <summary>
    /// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// A User's location. eh: "Bolivia, USA, France, Italy"
    /// </summary>
    public string Location { get; set; }

    public int Endorsements { get; set; } //Todo.
    public string Team { get; set; } //Todo.

    /// <summary>
    /// A collection of the User's linked accounts.
    /// </summary>
    public List<Account> Accounts { get; set; }

    /// <summary>
    /// A collection of the User's awarded badges.
    /// </summary>
    public List<Badge> Badges { get; set; }

}

そして、JSON応答をUserオブジェクトに逆シリアル化するために使用しているメソッド(この実際のJSON呼び出しはここにあります):

private User LoadUserFromJson(string response)
{
    var outObject = JsonConvert.DeserializeObject<User>(response);
    return outObject;
}

これにより、例外が発生します。

現在のJSONオブジェクト(例:{"name": "value"})をタイプ'System.Collections.Generic.List`1 [CoderwallDotNet.Api.Models.Account]'に逆シリアル化できません。これは、タイプにJSON配列が必要なためです(例:[ 1,2,3])正しく逆シリアル化する。

このエラーを修正するには、JSONをJSON配列([1,2,3]など)に変更するか、逆シリアル化された型を通常の.NET型(整数などのプリミティブ型ではなく、次のようなコレクション型ではない)になるように変更します。 JSONオブジェクトから逆シリアル化できる配列またはリスト)。JsonObjectAttributeを型に追加して、JSONオブジェクトから強制的に逆シリアル化することもできます。パス'accounts.github'、行1、位置129。

これまでこのDeserializeObjectメソッドを使用したことがないので、ここで立ち往生しています。

POCOクラスのプロパティ名がJSON応答の名前と同じであることを確認しました。

JSONをこのPOCOクラスに逆シリアル化するにはどうすればよいですか?

4

9 に答える 9

121

これが実際の例です。

キーポイントは次のとおりです。

  • の宣言Accounts
  • JsonProperty属性の使用

using (WebClient wc = new WebClient())
{
    var json = wc.DownloadString("http://coderwall.com/mdeiters.json");
    var user = JsonConvert.DeserializeObject<User>(json);
}

-

public class User
{
    /// <summary>
    /// A User's username. eg: "sergiotapia, mrkibbles, matumbo"
    /// </summary>
    [JsonProperty("username")]
    public string Username { get; set; }

    /// <summary>
    /// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
    /// </summary>
    [JsonProperty("name")]
    public string Name { get; set; }

    /// <summary>
    /// A User's location. eh: "Bolivia, USA, France, Italy"
    /// </summary>
    [JsonProperty("location")]
    public string Location { get; set; }

    [JsonProperty("endorsements")]
    public int Endorsements { get; set; } //Todo.

    [JsonProperty("team")]
    public string Team { get; set; } //Todo.

    /// <summary>
    /// A collection of the User's linked accounts.
    /// </summary>
    [JsonProperty("accounts")]
    public Account Accounts { get; set; }

    /// <summary>
    /// A collection of the User's awarded badges.
    /// </summary>
    [JsonProperty("badges")]
    public List<Badge> Badges { get; set; }
}

public class Account
{
    public string github;
}

public class Badge
{
    [JsonProperty("name")]
    public string Name;
    [JsonProperty("description")]
    public string Description;
    [JsonProperty("created")]
    public string Created;
    [JsonProperty("badge")]
    public string BadgeUrl;
}
于 2012-06-20T20:12:34.173 に答える
9

キャメルケースのJSON文字列をパスカルケースのPOCOオブジェクトに逆シリアル化する別の、より合理化されたアプローチは、CamelCasePropertyNamesContractResolverを使用することです。

これは、Newtonsoft.Json.Serialization名前空間の一部です。このアプローチでは、JSONオブジェクトとPOCOの唯一の違いは、プロパティ名の大文字と小文字にあると想定しています。プロパティ名のスペルが異なる場合は、JsonProperty属性を使用してプロパティ名をマップする必要があります。

using Newtonsoft.Json; 
using Newtonsoft.Json.Serialization;

. . .

private User LoadUserFromJson(string response) 
{
    JsonSerializerSettings serSettings = new JsonSerializerSettings();
    serSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    User outObject = JsonConvert.DeserializeObject<User>(jsonValue, serSettings);

    return outObject; 
}
于 2014-12-19T22:05:46.937 に答える
6

を作成できますJsonConverter。あなたの質問に似た例については、ここを参照してください。

于 2012-06-20T19:07:29.657 に答える
5

accountsプロパティは次のように定義されます。

"accounts":{"github":"sergiotapia"}

あなたのPOCOはこれを述べています:

public List<Account> Accounts { get; set; }

このJsonを使用してみてください:

"accounts":[{"github":"sergiotapia"}]

アイテムの配列(リストにマップされる予定)は、常に角括弧で囲まれています。

編集:アカウントポコは次のようになります:

class Account {
    public string github { get; set; }
}

そして多分他の特性。

編集2:配列を持たないようにするには、次のようにプロパティを使用します。

public Account Accounts { get; set; }

最初の編集で投稿したサンプルクラスのようなもので。

于 2012-06-20T18:59:41.810 に答える
4

受け入れられた回答に沿って、JSONテキストサンプルがある場合は、それをこのコンバーターにプラグインし、オプションを選択してC#コードを生成できます。

実行時にタイプがわからない場合、このトピックは適切であるように見えます。

渡された任意のオブジェクトにjsonを動的に逆シリアル化します。c#

于 2017-02-27T23:24:32.633 に答える
3
to fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the
deserialized type so that it is a normal .NET type (e.g. not a primitive type like
integer, not a collection type like an array or List) that can be deserialized from a
JSON object.`

メッセージ全体は、Listオブジェクトにシリアル化できることを示していますが、入力はJSONリストである必要があります。これは、JSONに含まれている必要があることを意味します

"accounts" : [{<AccountObjectData}, {<AccountObjectData>}...],

AccountObjectデータは、AccountオブジェクトまたはBadgeオブジェクトを表すJSONです。

現在取得しているように見えるのは

"accounts":{"github":"sergiotapia"}

accountsはJSONオブジェクト(中括弧で示されます)であり、JSONオブジェクトの配列(配列は角かっこで示されます)ではありません。これは必要なものです。試す

"accounts" : [{"github":"sergiotapia"}]
于 2012-06-20T19:02:35.283 に答える
0

それは私が考えていたものとはまったく異なります。実行時にのみ認識されるジェネリック型がある場合はどうしますか?

public MyDTO toObject() {
  try {
    var methodInfo = MethodBase.GetCurrentMethod();
    if (methodInfo.DeclaringType != null) {
      var fullName = methodInfo.DeclaringType.FullName + "." + this.dtoName;
      Type type = Type.GetType(fullName);
      if (type != null) {
        var obj = JsonConvert.DeserializeObject(payload);
      //var obj = JsonConvert.DeserializeObject<type.MemberType.GetType()>(payload);  // <--- type ?????
          ...
      }
    }

    // Example for java..   Convert this to C#
    return JSONUtil.fromJSON(payload, Class.forName(dtoName, false, getClass().getClassLoader()));
  } catch (Exception ex) {
    throw new ReflectInsightException(MethodBase.GetCurrentMethod().Name, ex);
  }
}
于 2015-02-26T18:30:48.097 に答える
0

遅れるかもしれませんが、QuickTypeを使用するのが最も簡単な方法です。

https://app.quicktype.io/

于 2021-11-11T22:58:48.783 に答える
0

この問題を抱えている人にとって、私はjson値を正しく見ていませんでした。https://jsonutils.com/ここで、生成する必要のあるクラスを確認し、コードでjsonを読み取ると、それらのクラスの1つだけを返すことができます。

たとえば、ブックリストオブジェクトが必要だったので、コードは1つだけ読み取る必要があります

res = await response.Content.ReadAsAsync<BookList>();

ブックリストは次のようになります

    public class BookList
    {

        [JsonProperty("data")]
        public IList<Datum> Data { get; set; }
     }

そして、そのリストには、Datumという名前のコンバーター(本だけ)よりも小さな本の留め金があります

    public class Datum
    {

        [JsonProperty("id")]
        public string Id { get; set; }

        [JsonProperty("isbn")]
        public string Isbn { get; set; }
    }

繰り返しますが、疑問がある場合はhttps://jsonutils.com/

于 2021-11-23T22:31:17.407 に答える