Пользовательский преобразователь контрактов JSON для игнорирования всех свойств без пользовательской аннотации - PullRequest
1 голос
/ 07 августа 2020

Я хочу объединить [JsonProperty("name")] и ![JsonIgnore] в свой собственный преобразователь, и мне просто нужна помощь по синтаксису.

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

public class MyClass
{
    [MyCustomProperty("name")]
    public string SomeName { get; set; }

    [MyCustomProperty("value")]
    public string SomeValue { get; set; }
    
    public string AnotherName {get; set; }
    
    public string AnotherValue {get; set; }
}

Ожидаемый результат:

{
    "name": "Apple",
    "value": "Delicious"
}

Вот как далеко я продвинулся с моим преобразователем:

public class MyCustomProperty : Attribute
{
    public string Property { get; set; }
    public MyCustomProperty(string property)
    {
        Property = property;
    }
}

public class CustomResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        Type itemType = property.PropertyType.GetGenericArguments().First();
        MyCustomProperty customProperty = itemType.GetCustomAttribute<MyCustomProperty>();
        property.PropertyName = MyCustomProperty.Property;
        return property;
    }
}

Я не совсем уверен, куда добавить игнорировать, если нет атрибута часть.

1 Ответ

1 голос
/ 07 августа 2020

JsonProperty имеет на нем AttributeProvider, который вы можете использовать для поиска настраиваемых атрибутов этого свойства. Я рекомендую вам использовать это. Таким образом, в основном вы должны попытаться получить атрибут, и, если он существует, вы задаете имя, как вы делаете, иначе вы устанавливаете Ignored = true.

В стороне, я бы рекомендовал вам переименовать свой MyCustomProperty class на MyCustomPropertyAttribute в соответствии со стандартными соглашениями для классов, производных от System.Attribute. (Не волнуйтесь, аннотацию [MyCustomProperty("name")] изменять не нужно, поскольку часть Attribute не является обязательной в аннотациях.) Вы также должны применить атрибут [AttributeUsage] к своему классу настраиваемого атрибута, чтобы указать, как его разрешено использовать. Наконец, я рекомендую вам переименовать Property в PropertyName, чтобы было ясно, что это имя (строка), а не само свойство (например, PropertyInfo).

Таким образом, код будет выглядеть так :

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class MyCustomPropertyAttribute : Attribute
{
    public string PropertyName { get; set; }
    public MyCustomPropertyAttribute(string propertyName)
    {
        PropertyName = propertyName;
    }
}

public class CustomResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        MyCustomPropertyAttribute customAttribute = (MyCustomPropertyAttribute)property.AttributeProvider.GetAttributes(typeof(MyCustomPropertyAttribute), true).FirstOrDefault();
        if (customAttribute != null)
        {
            property.PropertyName = customAttribute.PropertyName;
        }
        else
        {
            property.Ignored = true;
        }
        return property;
    }
}

Рабочая демонстрация: https://dotnetfiddle.net/thQc0f

Все это говорит о том, что вам действительно не нужен специальный преобразователь, чтобы получить желаемое поведение. Вы можете просто применить атрибут [JsonObject(MemberSerialization.OptIn)] к MyClass, а затем использовать обычные атрибуты [JsonProperty] для тех свойств, которые вы хотите включить. Любые не отмеченные свойства будут проигнорированы. (См. Атрибуты сериализации в документации Json. Net.)

[JsonObject(MemberSerialization.OptIn)]
public class MyClass
{
    [JsonProperty("name")]
    public string SomeName { get; set; }

    [MyCustomProperty("value")]
    public string SomeValue { get; set; }
    
    public string AnotherName {get; set; }
    
    public string AnotherValue {get; set; }
}

Демо: https://dotnetfiddle.net/qY6nGR

...