Мне нужна десериализация Newtonsoft JSON, чтобы пропустить запись в данном словаре JSON - PullRequest
0 голосов
/ 08 марта 2020

У меня есть этот класс в качестве моей JSON схемы (это правильный термин?):

class BasicInfoDatabase : Dictionary<string, BasicInfo>,
    IDictionary<string, BasicInfo>, 
    ICollection<KeyValuePair<string, BasicInfo>>, 
    IDictionary, 
    ICollection,
    IReadOnlyDictionary<string, BasicInfo>, 
    IReadOnlyCollection<KeyValuePair<string, BasicInfo>>,
    IEnumerable<KeyValuePair<string, BasicInfo>>, 
    IEnumerable, 
    ISerializable, 
    IDeserializationCallback 
{ }

Примечание: все интерфейсы Dictionary указаны здесь для решения несвязанных ошибки. В противном случае я бы их пропустил.

Во входной строке JSON есть запись, которая не отформатирована как объект BasicInfo. Я хотел бы игнорировать эту указанную запись c при десериализации входной строки. Вот код, который я использую для этого использования:

private static bool HandleInfoReceipt( string jsonStr, out BasicInfoDatabase infoDb ) {
    infoDb = new BasicInfoDatabase();

    JObject respJson = JObject.Parse( jsonStr );
    if( respJson.Count == 0 ) {
        return false;
    }

    infoDb = respJson.ToObject<BasicInfoDatabase>();
    if( infoDb == null ) {
        throw new NullReferenceException( "No info found" );
    }

    return true;
}

Как мне пропустить эту запись?

Ответы [ 2 ]

0 голосов
/ 10 марта 2020

Отфильтровать свойства из JObject довольно просто. То, как вы это сделаете, зависит от того, что вы знаете о JSON, а что нет.

Например, предположим, что ваш класс BasicInfo определен так:

class BasicInfo
{ 
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Amount { get; set; }
}

И ваш JSON выглядит следующим образом:

{
  "good": {
    "Id": 1,
    "Name": "Foo",
    "Amount": 14.95
  },
  "acceptable": {
    "Id": 2,
    "Name": "Bar"
  },
  "suspect": {
    "Id": 3,
    "Hmm": "Blah"
  },
  "bad": {
    "Foo": "Bar",
    "Baz": "Quux"
  },
  "ugly": "total garbage"
}

Если вы знаете указанные c ключи, которые вызывают проблемы, вы можете создать простой метод расширения для их фильтрации, например:

public static void FilterOutUnwantedProperties(this JObject jo, params string[] keys)
{
    var unwantedProperties = jo.Properties().Where(jp => keys.Contains(jp.Name)).ToList();

    foreach (JProperty prop in unwantedProperties)
    {
        prop.Remove();
    }
}

Затем вызовите его из вашего HandleInfoReceipt метода следующим образом:

respJson.FilterOutUnwantedProperties("bad", "ugly");

Fiddle: https://dotnetfiddle.net/TfH6Fr


С другой стороны, может быть, вы не знаете ключи заранее или они динамические c. Возможно, лучшим подходом было бы сделать так, чтобы метод расширения проверял, что каждое значение свойства в JObject фактически является самим объектом, и проверяет имена свойств объекта child , чтобы убедиться, что хотя бы одно из них (или все их?) соответствуют желаемому типу элемента. Это может выглядеть примерно так:

public static void FilterOutPropertiesThatAreNotCompatibleWith<TItem>(this JObject jo, BindingFlags flags=BindingFlags.Public|BindingFlags.Instance)
{
    var knownItemPropertyNames = 
        typeof(TItem).GetProperties(flags)
                     .Select(p => p.Name);
    var knownItemFieldNames = 
        typeof(TItem).GetFields(flags)
                     .Select(p => p.Name);
    var knownItemMemberNames = new HashSet<string>(knownItemPropertyNames);
    knownItemMemberNames.UnionWith(knownItemFieldNames);

    var unwantedProperties = 
        jo.Properties()
          .Where(jp => jp.Value.Type != JTokenType.Object ||
                       !jp.Value.Children<JProperty>()
                                .Any(cp => knownItemMemberNames.Contains(cp.Name)))
          .ToList();

    foreach (JProperty prop in unwantedProperties)
    {
        prop.Remove();
    }
}

Вы бы назвали эту версию так:

respJson.FilterOutPropertiesThatAreNotCompatibleWith<BasicInfo>();

Fiddle: https://dotnetfiddle.net/WsDmCE

0 голосов
/ 09 марта 2020

Примерно так:

 var result = new BasicInfoDatabase();
 var jObject = JObject.Parse( jsonStr );
 foreach (var kvp in jObject )
 {
     if(kvp.Key != "<property-you-want-to-skip>")
     {
         result.Add(kvp.Key, kvp.Value.ToObject<BasicInfo>());
     }  
 }

РЕДАКТИРОВАТЬ

Больше похоже на это:

kvp.Value.ToObject<BasicInfo>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...