通用解串器在一种情况下失败

问题描述 投票:0回答:1

我正在进行 http 调用,并且响应返回(已编辑)

{
  "Theaters": [
    {
      "id": "259cf043-6195-42dd-bfdb-640969e0bfb9",
      "name": "Theater1",
      "slug": "Theater1",
      "shows": [
        {
          "id": "73436465-1f14-400f-bfbf-ab6766269e70",
          "name": "show1"
        },
        {
          "id": "9a268b42-4f13-4f7a-9c7d-d40a30d7a6eb",
          "name": "show2"
        }
      ]
    },
    {
      "id": "9c6a0933-e519-4d6e-b027-e6c47c60641b",
      "name": "Theater3",
      "slug": "Theater3",
      "parks": [
        {
          "id": "18608db3e-fa23-4284-89dd-9fcd0wes9c9c",
          "name": "show3"
        }
      ]
    }
  ]
}

我的 C# 课程是:

public class Theater
{
    public Theater()
    {
        shows = new List<ShowBase>();
    }
    public string id { get; set; }
    public string name { get; set; }

    public string slug { get; set; }

    public ICollection<ShowBase> shows { get; set; }

}

public class ShowBase
{
    public string id { get; set; }
    public string name { get; set; }

}

public class TheaterList
{
    public TheaterList()
    {
        theaters= new List<Theater>();
    }
    public List<Theater> theaters;
}

我正在使用通用函数来获取结果

public virtual async Task<T> Get<T>()
{
    response = await client.GetAsync(URL);
    Console.WriteLine(response.IsSuccessStatusCode);
    string json = await response.Content.ReadAsStringAsync();
    var data = JsonSerializer.Deserialize<T>(json);
    return (T)Convert.ChangeType(data, typeof(T));
}

此有效负载返回空而失败 我用两种方式调用它

var result = await TheaterGetter.Get<TheaterList>();

var result = await TheaterGetter.Get<Theater>();

两者都空空回来,不应该。

我也尝试过这个,但收到错误消息,指出需要实施

IConvertible

var result = await TheaterGetter.GetList<List<Theater>, Theater>();
public virtual async Task<List<T>> GetList<T, B>()
{
    response = await client.GetAsync(URL);
    Console.WriteLine(response.IsSuccessStatusCode);
    string json = await response.Content.ReadAsStringAsync();
    var data = JsonSerializer.Deserialize<B>(json);
    return (List<T>)Convert.ChangeType(data, typeof(T));
}

如有任何帮助,我们将不胜感激

c# json generics deserialization
1个回答
0
投票

您在这里遇到一些问题:

  1. public List<Theater> theaters;
    field 不是属性,但 System.Text.Json 默认情况下不会序列化字段。 您需要将
    JsonSerializerOptions.IncludeFields
    设置为 true 或将该字段更改为属性。

  2. System.Text.Json 默认情况下区分大小写,但字段名称

    theaters
    与 JSON 属性名称
    "Theaters"
    不匹配。 您需要使它们一致或使用 JsonSerializer.Deserialize 失败System.Text.Json 中 Newtonsoft.Json 的 JsonProperty 属性的等效项是什么?.

    中的替代方案之一
  3. 您的根 JSON 对象对应于

    TheaterList
    ,因此您需要在
    Get<T>()
    方法中使用该类型。

  4. 您将获得

    string
    形式的响应,然后手动反序列化该字符串。 虽然这可行,但它不会像调用
    HttpClientJsonExtensions.GetFromJsonAsync()
    那样高效,后者从响应流中异步反序列化,而无需中间
    string
    表示。

  5. 尚不清楚您是否需要这个,但您的

    Theater
    类型没有与 JSON 属性对应的属性
    "parks"

  6. Get<T>()
    方法的第一个版本中,您调用

    (T)Convert.ChangeType(data, typeof(T));
    

    这不是必需的,因为

    data
    已经是
    T
    类型。

    在你的第二个版本中,你调用:

    (List<T>)Convert.ChangeType(data, typeof(T));
    

    这是行不通的。 看来您正在尝试以某种通用方式返回

    TheaterList.Theaters
    的值,但 C# 没有内置架构来一般从一种类型转换为另一种类型,因为
    Convert.ChangeType()
    主要用于从 或 转换到原始类型,如
    string
    int

要修复#1-#5,请按如下方式修改 C# 类:

public class TheaterList
{
    public List<Theater> Theaters { get; set; } = new(); // FIXED - made a property and capitalized the first letter
}

public class Theater
{
    public string id { get; set; }
    public string name { get; set; }
    public string slug { get; set; }

    public ICollection<ShowBase> shows { get; set; } = new List<ShowBase>();
    public ICollection<ShowBase> parks { get; set; } = new List<ShowBase>(); // TODO: include only if required
}

public class ShowBase
{
    public string id { get; set; }
    public string name { get; set; }
}

你的

TheaterGetter.Get<TValue>()
方法如下:

public virtual async Task<TValue?> Get<TValue>(CancellationToken cancellationToken = default) =>
    await client.GetFromJsonAsync<TValue?>(URL, cancellationToken : cancellationToken);

然后调用如下:

var result = (await TheaterGetter.Get<TheaterList>())
    ?.Theaters;

现在,如果您还需要修复#6——一种从

TheaterList
转换为
List<Theater>
的自动通用方法——那么没有内置任何内容,因此您需要自己完成。 一种可能性是创建一个通用接口和扩展方法,如下所示:

public interface IConvertibleTo<out TToType>
{
    TToType ConvertTo();
}

public static class ConvertibleExtensions
{
    public static TToType? ConvertTo<TToType>(this IConvertibleTo<TToType>? from) => from is null ? default(TToType?) : from.ConvertTo();
}

然后让

TheaterList
实现接口:

public class TheaterList : IConvertibleTo<List<Theater>>
{
    List<Theater> IConvertibleTo<List<Theater>>.ConvertTo() => Theaters;

    public List<Theater> Theaters { get; set; } = new();
}

最后,您将能够添加一个

TheaterGetter.Get<TDto, TValue>
方法,自动反序列化剧院列表并将其转换为剧院列表,如下所示:

public virtual async Task<TValue?> Get<TDto, TValue>(CancellationToken cancellationToken = default) 
    where TDto : IConvertibleTo<TValue> =>
    (await Get<TDto?>(cancellationToken)).ConvertTo<TValue>();

并这样称呼它:

var result = await TheaterGetter.Get<TheaterList, List<Theater>>();

演示 #2 此处

© www.soinside.com 2019 - 2024. All rights reserved.