Можно ли обойтись без атрибутов в JSON
От: Passerby  
Дата: 24.08.19 15:11
Оценка:
К нескольким сообщениям из разных источников применяется:
JsonConvert.DeserializeObject<List<OKeX_Json.RootObject>>(message);

При этом создаются объекты с одинаковыми названиями свойств, т.к. применяются атрибуты. Но классы разные.
Пример для одного свойства:
//для сообщения из одного источника:
public class RootObject1
    {
       [JsonProperty(PropertyName = "sell")]
            public decimal ask { get; set; }
}
//Для сообщения из другого источника:
public class RootObject2
    {
       [JsonProperty(PropertyName = "best_ask")]
            public decimal ask { get; set; }
}
//Еще из какого-то источника:
public class RootObject3
    {
       [JsonProperty(PropertyName = "Ask")]
            public decimal ask { get; set; }
}

Все объекты одинаково обрабатываются, потому хочется чтобы была только одна функция их обработки.
Существуют ли параметры метода DeserializeObject, которые бы форматировали названия свойств, так, как это делают атрибуты? Т.е. можно ли сделать только один public class RootObject для все источников сообщений
public class RootObject
    {       
            public decimal ask { get; set; }
}

а роль атрибутов играли бы параметры DeserializeObject?
Или одну и ту же функцию обработки объектов в данном случае можно сделать только применяя dynamic?
Re: Можно ли обойтись без атрибутов в JSON
От: Passerby  
Дата: 24.08.19 15:22
Оценка:
Или передавать в функцию object с дальнейшим приведением типа?
Re: Можно ли обойтись без атрибутов в JSON
От: RushDevion Россия  
Дата: 24.08.19 15:52
Оценка: 3 (1) +1
Если я правильно понял, ты хочешь универсальную функцию обработки данных, прочитанных из json.
При этом структура json разная.
Один вариант — выделить интерфейс:
IDataObject
 decimal Ask {get;set;}
И реализовать его в каждом из DTO RootObject1..3.
Тогда функция обработки будет универсальной:
public void Process(IDataObject data) { ... }
 decimal Ask {get;set;}

Другой вариант.
Реализовать свой ContractResoler и подсунуть его в JsonConvert.DeserializeObject.
Вот тут подробнее.
Re: Можно ли обойтись без атрибутов в JSON
От: Слава  
Дата: 24.08.19 15:55
Оценка: 2 (1) +1
Здравствуйте, Passerby, Вы писали:

P>Существуют ли параметры метода DeserializeObject, которые бы форматировали названия свойств, так, как это делают атрибуты? Т.е. можно ли сделать только один public


Можно специальный десериализатор подавать
https://www.jerriepelser.com/blog/deserialize-different-json-object-same-class/

А с dynamic'ами я бы связываться не стал, только как быстрое решение — и то JObject будет лучше.
Re: Можно ли обойтись без атрибутов в JSON
От: VladCore  
Дата: 24.08.19 18:43
Оценка: 2 (1)
Здравствуйте, Passerby, Вы писали:

P>К нескольким сообщениям из разных источников применяется:

P>При этом создаются объекты с одинаковыми названиями свойств, т.к. применяются атрибуты. Но классы разные.
P>Пример для одного свойства:

P>Все объекты одинаково обрабатываются, потому хочется чтобы была только одна функция их обработки.

P>Существуют ли параметры метода DeserializeObject, которые бы форматировали названия свойств, так, как это делают атрибуты? Т.е. можно ли сделать только один public class RootObject для все источников сообщений

Можно.


public class CustomDataContractResolver : DefaultContractResolver
{
  public static readonly CustomDataContractResolver Instance = new CustomDataContractResolver ();

  protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
  {
    var property = base.CreateProperty(member, memberSerialization);
    if (property.DeclaringType == typeof(MyCustomObject))
    {
      if (property.PropertyName.Equals("LongPropertyName", StringComparison.OrdinalIgnoreCase))
      {
        property.PropertyName = "Short";
      }
    }
    return property;
  }
}


https://stackoverflow.com/a/33290710

Показывайте нужно ли?
Re[2]: Можно ли обойтись без атрибутов в JSON
От: Passerby  
Дата: 25.08.19 00:27
Оценка:
Здравствуйте, VladCore, Вы писали:

VC>Здравствуйте, Passerby, Вы писали:


P>>К нескольким сообщениям из разных источников применяется:

P>>При этом создаются объекты с одинаковыми названиями свойств, т.к. применяются атрибуты. Но классы разные.
P>>Пример для одного свойства:

P>>Все объекты одинаково обрабатываются, потому хочется чтобы была только одна функция их обработки.

P>>Существуют ли параметры метода DeserializeObject, которые бы форматировали названия свойств, так, как это делают атрибуты? Т.е. можно ли сделать только один public class RootObject для все источников сообщений

VC>Можно.



VC>
VC>public class CustomDataContractResolver : DefaultContractResolver
VC>{
VC>  public static readonly CustomDataContractResolver Instance = new CustomDataContractResolver ();

VC>  protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
VC>  {
VC>    var property = base.CreateProperty(member, memberSerialization);
VC>    if (property.DeclaringType == typeof(MyCustomObject))
VC>    {
VC>      if (property.PropertyName.Equals("LongPropertyName", StringComparison.OrdinalIgnoreCase))
VC>      {
VC>        property.PropertyName = "Short";
VC>      }
VC>    }
VC>    return property;
VC>  }
VC>}
VC>


VC>https://stackoverflow.com/a/33290710


VC>Показывайте нужно ли?

Всем спасибо.
Хотя вариант с интерфейсом достаточно прост, пытался разобраться с конверторами.
Почему-то не удалось.
В варианте https://stackoverflow.com/questions/8796618/how-can-i-change-property-names-when-serializing-with-json-net/33290710#33290710 показан пример сериализации. Мне нужна десериализация. Пробовал аналогично примеру, создавая в RootObject свойства с новыми именами, но не проходит.
Пробовал вариант https://www.jerriepelser.com/blog/deserialize-different-json-object-same-class/
Добавлял в RootObject свойства с новыми именами, удалял старые имена, оставлял все как было, — в любом случае во время отладки ошибка. Сделал словарь старые имена — новые имена пустым — все равно ошибка "System.NullReferenceException: "Ссылка на объект не указывает на экземпляр объекта." System.Reflection.CustomAttributeExtensions.GetCustomAttribute<T>(...) вернул null." на строке pi.CanWrite && pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);
Re[3]: Можно ли обойтись без атрибутов в JSON
От: Qulac Россия  
Дата: 25.08.19 09:36
Оценка:
Здравствуйте, Passerby, Вы писали:

P>Здравствуйте, VladCore, Вы писали:


VC>>Здравствуйте, Passerby, Вы писали:


P>>>К нескольким сообщениям из разных источников применяется:

P>>>При этом создаются объекты с одинаковыми названиями свойств, т.к. применяются атрибуты. Но классы разные.
P>>>Пример для одного свойства:

P>>>Все объекты одинаково обрабатываются, потому хочется чтобы была только одна функция их обработки.

P>>>Существуют ли параметры метода DeserializeObject, которые бы форматировали названия свойств, так, как это делают атрибуты? Т.е. можно ли сделать только один public class RootObject для все источников сообщений

VC>>Можно.



VC>>
VC>>public class CustomDataContractResolver : DefaultContractResolver
VC>>{
VC>>  public static readonly CustomDataContractResolver Instance = new CustomDataContractResolver ();

VC>>  protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
VC>>  {
VC>>    var property = base.CreateProperty(member, memberSerialization);
VC>>    if (property.DeclaringType == typeof(MyCustomObject))
VC>>    {
VC>>      if (property.PropertyName.Equals("LongPropertyName", StringComparison.OrdinalIgnoreCase))
VC>>      {
VC>>        property.PropertyName = "Short";
VC>>      }
VC>>    }
VC>>    return property;
VC>>  }
VC>>}
VC>>


VC>>https://stackoverflow.com/a/33290710


VC>>Показывайте нужно ли?

P>Всем спасибо.
P>Хотя вариант с интерфейсом достаточно прост, пытался разобраться с конверторами.
P>Почему-то не удалось.
P>В варианте https://stackoverflow.com/questions/8796618/how-can-i-change-property-names-when-serializing-with-json-net/33290710#33290710 показан пример сериализации. Мне нужна десериализация. Пробовал аналогично примеру, создавая в RootObject свойства с новыми именами, но не проходит.
P>Пробовал вариант https://www.jerriepelser.com/blog/deserialize-different-json-object-same-class/
P>Добавлял в RootObject свойства с новыми именами, удалял старые имена, оставлял все как было, — в любом случае во время отладки ошибка. Сделал словарь старые имена — новые имена пустым — все равно ошибка "System.NullReferenceException: "Ссылка на объект не указывает на экземпляр объекта." System.Reflection.CustomAttributeExtensions.GetCustomAttribute<T>(...) вернул null." на строке pi.CanWrite && pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);

А рефлексия не вариант, что бы одну функцию сделать?
Программа – это мысли спрессованные в код
Re: Можно ли обойтись без атрибутов в JSON
От: Kolesiki  
Дата: 25.08.19 18:27
Оценка:
Здравствуйте, Passerby, Вы писали:

P> [JsonProperty(PropertyName = "sell")]

P> public decimal ask { get; set; }

P> [JsonProperty(PropertyName = "best_ask")]

P> public decimal ask { get; set; }

P> [JsonProperty(PropertyName = "Ask")]

P> public decimal ask { get; set; }

Какая-то дурацкая схема... Зачем разные имена одному и тому же параметру?? Тут наоборот задача: разные проперти смэпить в одну.
Так, для справки: передача ask будет выглядеть примерно так:

{
    "ask": "123"
}


Такую строку можно десериализовать в ЛЮБОЙ объект, содержащий проперть/филд ask.
Более того: есть такой метод как PopulateObject — с ним вообще можете свой ask наложить на объект ЛЮБОГО типа с одноимённым мембером.
Отредактировано 25.08.2019 18:30 Kolesiki . Предыдущая версия .
Re[2]: Можно ли обойтись без атрибутов в JSON
От: Doc Россия http://andrey.moveax.ru
Дата: 26.08.19 06:57
Оценка: +3 :))
Здравствуйте, Kolesiki, Вы писали:

K>Какая-то дурацкая схема... Зачем разные имена одному и тому же параметру??


И правда, как так вышло что разные сервисы назвали параметр по разному? :D Никогда такого не было, и вот опять...
Re: Можно ли обойтись без атрибутов в JSON
От: Doc Россия http://andrey.moveax.ru
Дата: 26.08.19 07:03
Оценка: +1
Здравствуйте, Passerby, Вы писали:

Ну что можно вам уже подсказали. Вопрос у меня был бы — нужно ли?
В каждом случае имя параметра это часть контракта сервиса. Поэтому я бы не смешивал их и разделил так
1) для каждого источника свой класс-контракт со своими именами свойств, соответствующими входным данным
2) для каждого источника данных определен метод, который мапит контракт на сущность из BL (которая разумеется одна и содержит уже только то нужно для BL, и скорее всего не совпадает 1 в 1 с контрактами)
По сути получаются адаптеры для источников.

IMHO кода не намного больше, но зато гораздо меньше шансов сломать что-то для одного источника, пока правишь что-то для другого.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.