2012-03-07 2 views
1

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

Пусть у меня есть класс игрока в моем коде .NET, который выглядит следующим образом:

public class Player 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public long Score { get; set; } 
} 

Мне нужно сериализовать этот класс в строку JSON (используя JSON.NET) и использовать его при отправке в веб-службу. Однако дело в том, что некоторые из конечных точек службы явно запрещают в строке JSON появление определенных членов. Например, конечная точка «post score» позволит включить все три члена в строку, в то время как конечная точка «player player» будет содержать только идентификатор и имя (в противном случае неудачный запрос возвращается клиенту). Теперь я знаю, что могу сделать 2 разных класса (например, Player и CompetitivePlayer), каждый из которых содержит требуемый (дополнительный) набор участников, однако для практических целей предположим, что я не могу этого сделать или хочу избежать этого (мои фактические объекты данных более сложны, чем приведенный здесь класс Player просто как пример).

Так что на самом деле я хочу сказать сериализатору JSON во время выполнения, что в ситуации X должны быть сериализованы только некоторые члены объекта, а в ситуации Y - сериализуемое целое другое подмножество. Сначала я думал, что реализация моего собственного ContractResolver поможет, но, как оказалось, это называется только один раз для типа объекта, а не для самого объекта при его сериализации. Теперь единственным решением, которое я могу придумать, является подкласс JSONSerializer и использовать JSONWriter, который игнорирует свойства, имена которых включены в список строк, заданных как аргумент, возможно, хотя я не совсем уверен, может ли этот план работать. Есть ли более простое решение для того, чего я пытаюсь достичь?

ответ

3

Хорошо, посмотрев исходный код JSON.NET, я нашел точное место, которое мешало мне настраивать сериализацию этих свойств: класс CamelCasePropertyNamesContractResolver.

Прежде чем написать оригинальный вопрос, я попытался реализовать пользовательскую сериализацию, как описано здесь, в разделе IContractResolver. Однако вместо наследования непосредственно из DefaultContractResolver я использовал CamelCasePropertyNamesContractResolver (здесь мне нужен случай с верблюдом), который, посмотрев внутри своего кода, устанавливает флаг «share cache», который предотвращает вызов некоторых из его методов по причинам производительности (что я ' м, желающих пожертвовать в этом сценарии). Таким образом, CreateProperties() вызывается только один раз для каждого типа объекта, а не каждый раз, когда мой объект должен быть сериализован. Так что теперь мой контракт класс распознавателя выглядит следующим образом:

class OptionalPropertiesContractResolver : DefaultContractResolver 
{ 
    //only the properties whose names are included in this list will be serialized 
    IEnumerable<string> _includedProperties; 

    public OptionalPropertiesContractResolver(IEnumerable<string> includedProperties) 
    { 
     _includedProperties = includedProperties; 
    } 

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     return (from prop in base.CreateProperties(type, memberSerialization) 
       where _includedProperties.Contains(prop.PropertyName) 
       select prop).ToList(); 
    } 

    protected override string ResolvePropertyName(string propertyName) 
    { 
     // lower case the first letter of the passed in name 
     return ToCamelCase(propertyName); 
    } 

    static string ToCamelCase(string s) 
    { 
     //camel case implementation 
    } 
} 

Просто хотел, чтобы другие знали об этой конкретной ситуации в случае, если они когда-либо попадались.

+1

Если ваш ответ является наиболее правильным, вы можете принять свой собственный ответ. – arcain

+0

И ваша щедрость окупилась, так как это именно та ситуация, с которой я столкнулся сегодня. Благодаря! –

0

Я бы создал классы контрактов и использовал AutoMapper для сопоставления им с классом Player и сериализовал их по мере необходимости. То есть «PlayerContract», «CompetitivePlayerContract» и т. Д.

Не имеет значения, что эти классы представляют только контракты на ваш сервис.

+0

Спасибо за предложение, хотя я бы предпочел не вводить другую библиотеку (AutoMapper) и создавать дополнительные классы. Я хотел бы решить это с помощью настроек только для JSON-сериализатора. Я буду помнить об этом, но если все остальное не удастся. –

Смежные вопросы