Я хочу, чтобы JSON & ldquo; пропустить & rdquo; десериализация объекта JSON в C # List < object > если член JSON отсутствует

Чтобы сделать вашу функцию более переносимой, используйте ее как таковой:

os.path.join(os.sep, 'home', 'build', 'test', 'sandboxes', todaystr, 'new_sandbox')

или

os.path.join(os.environ.get("HOME"), 'test', 'sandboxes', todaystr, 'new_sandbox')
1
задан dbc 15 January 2019 в 20:54
поделиться

1 ответ

Вы можете принять и расширить общий подход с этого ответа до Десериализацию полиморфных классов json без информации о типах, используя json.net или этот ответ - Как вызвать JsonConvert.DeserializeObject и отключить JsonConverter, примененный к базовому типу через [JsonConverter]? , создав пользовательский JsonConverter для List<IMachineInfo>, который выполняет следующее:

  1. Загружает каждую запись массива во временную JToken.
  2. Пытается вывести тип элемента из имеющихся параметров.
  3. Пропускает запись массива, если тип не может быть выведен.

Для этого сначала представьте общий конвертер базового класса следующим образом:

public abstract class JsonListItemTypeInferringConverterBase<TItem> : JsonConverter
{
    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    protected abstract bool TryInferItemType(Type objectType, JToken json, out Type type);

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Get contract information
        var contract = serializer.ContractResolver.ResolveContract(objectType) as JsonArrayContract;
        if (contract == null || contract.IsMultidimensionalArray || objectType.IsArray)
            throw new JsonSerializationException(string.Format("Invalid array contract for {0}", objectType));

        if (reader.MoveToContent().TokenType == JsonToken.Null)
            return null;

        if (reader.TokenType != JsonToken.StartArray)
            throw new JsonSerializationException(string.Format("Expected {0}, encountered {1} at path {2}", JsonToken.StartArray, reader.TokenType, reader.Path));

        var collection = existingValue as IList<TItem> ?? (IList<TItem>)contract.DefaultCreator();

        // Process the collection items
        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.EndArray:
                    return collection;

                case JsonToken.Comment:
                    break;

                default:
                    {
                        var token = JToken.Load(reader);
                        Type itemType;
                        if (!TryInferItemType(typeof(TItem), token, out itemType))
                            break;
                        collection.Add((TItem)serializer.Deserialize(token.CreateReader(), itemType));
                    }
                    break;
            }
        }
        // Should not come here.
        throw new JsonSerializationException("Unclosed array at path: " + reader.Path);
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsAssignableFrom(typeof(List<TItem>));
    }
}

public static partial class JsonExtensions
{
    public static JsonReader MoveToContent(this JsonReader reader)
    {
        while ((reader.TokenType == JsonToken.Comment || reader.TokenType == JsonToken.None) && reader.Read())
            ;
        return reader;
    }
}

Затем создайте конкретную версию, которая десериализует только записи списка типа Machine1 следующим образом: [1137 ]

public class Machine1ListConverter<TMachineInfo> : JsonListItemTypeInferringConverterBase<TMachineInfo> where TMachineInfo : IMachineInfo
{
    protected override bool TryInferItemType(Type objectType, JToken json, out Type type)
    {
        var obj = json as JObject;
        if (obj != null && obj.GetValue("powerWatts", StringComparison.OrdinalIgnoreCase) != null)
        {
            type = typeof(Machine1);
            return true;
        }
        type = null;
        return false;
    }
}

И, наконец, десериализовать вашу строку JSON следующим образом:

var settings = new JsonSerializerSettings
{
    Converters = { new Machine1ListConverter<IMachineInfo>() },
};
var list = JsonConvert.DeserializeObject<List<IMachineInfo>>(jsonString, settings);

Если вы хотите десериализовать в конкретный List<Machine1>, сделайте:

var settings = new JsonSerializerSettings
{
    Converters = { new Machine1ListConverter<Machine1>() },
};
var list = JsonConvert.DeserializeObject<List<Machine1>>(jsonString, settings);

Примечания:

  • Преобразователь необходимо применять ко всей коллекции вместо элементов коллекции, поскольку JsonConverter.ReadJson не имеет возможности пропускать токен, читаемый в данный момент, и предотвращать его возвращаемое значение после добавления в содержащий объект.

  • Для десериализации только элементов типа Machine2 вы можете аналогичным образом создать Machine2ListConverter, в котором TryInferItemType() проверяет наличие dbm.

  • Для десериализации вы звоните

    JsonConvert.DeserializeObject<List<Machine1>>(@"C/Path/jsonfile", settings);
    

    Но JsonConvert.DeserializeObject Method (String, JsonSerializerSettings) десериализует строку JSON, а не именованный файл. Для десериализации из файла см. Десериализацию JSON из файла .

Демонстрационная скрипка здесь .

0
ответ дан dbc 15 January 2019 в 20:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: