Skip to main content
Added attribute usage
Source Link
devklick
  • 2.7k
  • 7
  • 39
  • 72
[AttributeUsage(AttributeTargets.Field)]
public class AlternativeValueAttribute : Attribute
{
    public string JsonValue { get; set; }
    public string DbValue { get; set; }
    // and any other kind of alternative value you need...
}
public class AlternativeValueAttribute : Attribute
{
    public string JsonValue { get; set; }
    public string DbValue { get; set; }
    // and any other kind of alternative value you need...
}
[AttributeUsage(AttributeTargets.Field)]
public class AlternativeValueAttribute : Attribute
{
    public string JsonValue { get; set; }
    public string DbValue { get; set; }
    // and any other kind of alternative value you need...
}
Source Link
devklick
  • 2.7k
  • 7
  • 39
  • 72

Here's the approach I often take when faced with the same problem. (Here's a fiddle, if you want to jump straight to a working example)

###Setting up the enums

I often find myself needing alternative values for enums. For this reason, I like to create an attribute to store these alternative values. For example:

public class AlternativeValueAttribute : Attribute
{
    public string JsonValue { get; set; }
    public string DbValue { get; set; }
    // and any other kind of alternative value you need...
}

(Note, the DbValue property is irrelevant for the purpose of this demonstration... It's just to demonstrate holding multiple alternative values.)

And when building my enum object's, I use this attribute on each value that requires an alternative value. For example:

public enum ObjectState
{
    [AlternativeValue(DbValue = "-1", JsonValue="is-unknown")]
    Unknown,

    [AlternativeValue(DbValue = "1", JsonValue="is-active")]
    Active, 

    [AlternativeValue(DbValue = "0", JsonValue="is-inactive")]
    Inactive
    // ...
}

###Creating the converter

Now we need to create a converter to be able to utilise the alternative value. In this case, we're serialising/deserialising Json, so we'll create a JsonConverter:

public class AlternativeValueJsonConverter<TEnum> : JsonConverter where TEnum : struct, IConvertible, IComparable, IFormattable
{
    public override bool CanConvert( Type objectType )
    {
        // we can only convert if the type of object matches the generic type specified
        return objectType == typeof( TEnum );
    }

    public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
    {
        if( objectType == typeof(TEnum) )
        {
            // cycle through the enum values
            foreach(var item in (TEnum[])Enum.GetValues( typeof( TEnum ) ) )
            {
                // get the AlternativeValueAttribute, if it exists
                var attr = item.GetType().GetTypeInfo().GetRuntimeField( item.ToString() )
                    .GetCustomAttribute<AlternativeValueAttribute>();
                
                // if the JsonValue property matches the incoming value, 
                // return this enum value
                if (attr != null && attr.JsonValue == reader.Value.ToString())
                {
                    return item;
                }
            }
        }
        return null;
    }

    public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer )
    {
        if( value.GetType() == typeof( TEnum ) )
        {
            // cycle through the enum values
            foreach( var item in (TEnum[])Enum.GetValues( typeof( TEnum ) ) )
            {
                // if we've found the right enum value
                if (item.ToString() == value.ToString() )
                {
                    // get the attribute from the enum value
                    var attr = item.GetType().GetTypeInfo().GetRuntimeField( item.ToString() )
                        .GetCustomAttribute<AlternativeValueAttribute>();

                    if( attr != null)
                    {
                        // write out the JsonValue property's value
                        serializer.Serialize( writer, attr.JsonValue );
                    }
                }
            }
        }
    }
}

###Usage Lastly, to use this JsonConverter, we need to decorate our enum object with it. So the ObjectState enum we've already declared should be updated to use the converter. For example:

[JsonConverter(typeof(AlternativeValueJsonConverter<ObjectState>))]
public enum ObjectState
{
    [AlternativeValue(DbValue = "-1", JsonValue="is-unknown")]
    Unknown,

    [AlternativeValue(DbValue = "1", JsonValue="is-active")]
    Active, 

    [AlternativeValue(DbValue = "0", JsonValue="is-inactive")]
    Inactive
    // ...
}

Now, for demonstration purposes, we'll create a simple POCO that contains the ObjectState enum and convert it to Json to make sure we get the expected results:

public class DemoPoco
{
    public ObjectState MyObjectState { get; set; }
}

public static void Main( string[] args )
{
    DemoPoco demo = new DemoPoco { MyObjectState = ObjectState.Active };
    
    var json = JsonConvert.SerializeObject( demo );

    Console.WriteLine(json); // output: {"MyObjectState":"is-active"}
}