При этом создаются объекты с одинаковыми названиями свойств, т.к. применяются атрибуты. Но классы разные.
Пример для одного свойства:
//для сообщения из одного источника: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?
Если я правильно понял, ты хочешь универсальную функцию обработки данных, прочитанных из json.
При этом структура json разная.
Один вариант — выделить интерфейс:
IDataObject
decimal Ask {get;set;}
И реализовать его в каждом из DTO RootObject1..3.
Тогда функция обработки будет универсальной:
public void Process(IDataObject data) { ... }
decimal Ask {get;set;}
Другой вариант.
Реализовать свой ContractResoler и подсунуть его в JsonConvert.DeserializeObject. Вот тут подробнее.
Здравствуйте, Passerby, Вы писали:
P>Существуют ли параметры метода DeserializeObject, которые бы форматировали названия свойств, так, как это делают атрибуты? Т.е. можно ли сделать только один public
Здравствуйте, 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;
}
}
Здравствуйте, 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);
Здравствуйте, 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);
А рефлексия не вариант, что бы одну функцию сделать?
Здравствуйте, 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 наложить на объект ЛЮБОГО типа с одноимённым мембером.
Ну что можно вам уже подсказали. Вопрос у меня был бы — нужно ли?
В каждом случае имя параметра это часть контракта сервиса. Поэтому я бы не смешивал их и разделил так
1) для каждого источника свой класс-контракт со своими именами свойств, соответствующими входным данным
2) для каждого источника данных определен метод, который мапит контракт на сущность из BL (которая разумеется одна и содержит уже только то нужно для BL, и скорее всего не совпадает 1 в 1 с контрактами)
По сути получаются адаптеры для источников.
IMHO кода не намного больше, но зато гораздо меньше шансов сломать что-то для одного источника, пока правишь что-то для другого.