11

I have a class that I cannot change:

public enum MyEnum {
    Item1 = 0,
    Item2 = 1
}
public class foo {
    [JsonConverter(typeof(StringEnumConverter))]
    public MyEnum EnumTypes {get; set; }
}

Somewhere down the line JsonConvert.SerializeObject serializes the object and because of the JsonConverter attribute, it spits out name of the enum value for the foo.EnumTypes rather than the number.

Is there anyway to get JsonConvert.SerializeObject to ignore the attribute on the EnumTypes property?

AngryHacker
  • 59,598
  • 102
  • 325
  • 594
  • I think it depends on how you are using the foo class, if you are literally just serializing an instance of foo by itself then you could implement a version of the class that does not use the StringEnumConverter on the EnumTypes field and copy the field values over before serializing. Could you provide more information to give the question more context? – Kodaloid Aug 11 '17 at 21:31

5 Answers5

11

This is possible, but the process is a tad involved.

The basic idea is to create a custom ContractResolver and override its CreateProperty method. Something like so:

internal sealed class MyContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty( MemberInfo member, MemberSerialization memberSerialization )
    {
        var property = base.CreateProperty( member, memberSerialization );

        if( member.DeclaringType == typeof( foo ) && property.PropertyType == typeof( MyEnum ) )
        {
            property.Converter = null;
        }

        return property;
    }
}

You'll also need to actually instantiate this class and pass it into your serializer/deserializer. What that looks like depends on exactly how you're doing the serialization, so I can't guarantee a relevant example of how to use it.

If you're just using the static SerializeObject method:

JsonConvert.SerializeObject( valueToSerialize, new SerializerSettings { ContractResolver = new MyContractResolver() } );
Kyle
  • 6,500
  • 2
  • 31
  • 41
  • This looks promising. How do I pass it into the serializer? Do you have an example? – AngryHacker Aug 11 '17 at 22:17
  • @AngryHacker Like I said, it depends on exactly how you're doing the serialization. There are a number of different ways to do it. The documentation I linked to for `ContractResolver` has an example of one way you might do it, but it's not the only way. I'll edit the answer with an example, but I can't promise it'll work for you. – Kyle Aug 11 '17 at 22:21
  • I figured it out 5 seconds after I posted the comment. It's actually doing exactly what I need it to do. Perfect. – AngryHacker Aug 11 '17 at 22:22
2

The previous comment looked really promising, but for some reason it didn't work for me. I modified accepted answer to fit my needs. Here is the code if anyone ever needs it

public class IgnoreConvertersContractResolver : DefaultContractResolver
{
    private readonly Type[] _typesToIgnore;

    public IgnoreConvertersContractResolver(params Type[] typesToIgnore)
    {
        _typesToIgnore = typesToIgnore;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        var attributes = property.AttributeProvider.GetAttributes(false);

        foreach (var attribute in attributes)
        {
            if (attribute is JsonConverterAttribute converterAttribute 
                && _typesToIgnore.Contains(converterAttribute.ConverterType))
            {
                property.Converter = null;
                break;
            }
        }

        return property;
    }
Alex K.
  • 784
  • 5
  • 12
1

Kyle's answer is a great starting point. It works fine in this concrete simple example from question. But for me it didn't work recursively for the nested properties, at least with newtonsoft.json v12.0.3. Looking at what else can be overwritten in DefaultContractResolver I've found

public virtual JsonContract ResolveContract(Type type);

and it worked fine for nested properties:

    internal sealed class NumericEnumContractResolver : DefaultContractResolver
    {
        private Type _stringEnumConverterType = typeof(StringEnumConverter);

        protected override JsonConverter ResolveContractConverter(Type objectType)
        {
            var converter = base.ResolveContractConverter(objectType);

            if ((converter != null) &&
                (converter.GetType() == _stringEnumConverterType))
            {
                converter = null;
            }

            return converter;
        }
    }

and sample usage:

JsonConvert.SerializeObject(
    myObject,
    new SerializerSettings
    {
        ContractResolver = new NumericEnumContractResolver()
    });
sarh
  • 6,371
  • 4
  • 25
  • 29
1

You could use JsonIgnore attribute

public class Object
{
    public string Key { get; set; }

    [JsonIgnore]
    public string Value { get; set; }
}
harwex213
  • 11
  • 1
  • 1
0

I'm a simple man and I would create separate DTO, copy the data into that object and serialise this DTO and not the original object.

tymtam
  • 31,798
  • 8
  • 86
  • 126