JavaScriptSerializer: serialización JSON de enumeración como cadena

Tengo una clase que contiene un enum propiedad, y al serializar el objeto usando JavaScriptSerializer, mi resultado json contiene el valor entero de la enumeración en lugar de su string "nombre". ¿Hay alguna forma de obtener la enumeración como string en mi json sin tener que crear un personalizado JavaScriptConverter? Quizás hay un atributo que podría decorar el enum definición, o propiedad del objeto, con?

Como un ejemplo:

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }
    Gender Gender { get; set; }
}

Resultado deseado de json:

{ "Age": 35, "Gender": "Male" }

Lo ideal es buscar una respuesta con clases de marco .NET integradas, si no es posible, las alternativas (como Json.net) son bienvenidas.

preguntado el 14 de marzo de 10 a las 02:03

¿Cambiar a cuál? La respuesta más votada a favor no responde a la pregunta: sí, es útil en otros contextos, de ahí los votos, pero no tiene ningún uso práctico si está atascado con MS JavaScriptSerializer, ya que esencialmente lo está si usa métodos de página y , lo más importante, como lo requiere la pregunta. La respuesta aceptada dice que no es posible. Mi respuesta, mientras que un poco de truco hace el trabajo. -

27 Respuestas

No, no hay ningún atributo especial que pueda utilizar. JavaScriptSerializer serializa enums a sus valores numéricos y no a su representación de cadena. Debería utilizar la serialización personalizada para serializar el enum como su nombre en lugar de valor numérico.


Si puede usar JSON.Net en lugar de JavaScriptSerializer que ver responder a esta pregunta proporcionada por OmerBakhari: JSON.net cubre este caso de uso (a través del atributo [JsonConverter(typeof(StringEnumConverter))]) y muchos otros no manejados por los serializadores .net integrados. Aquí hay un enlace que compara características y funcionalidades de los serializadores..

Respondido el 25 de Septiembre de 19 a las 22:09

@Fabzter - su solución funcionó conmigo usando Newtonsoft's Json - BeemerGuy

@BornToCode Json.NET es el serializador que ASP.NET usa por defecto. - BrainSlugs83

@ BrainSlugs83: la pregunta era sobre el uso de JavaScriptSerializer, no Json.NET (y si observa el historial de revisiones, verá que hubo una edición para aclarar eso), si usa JavaScriptSerializer el atributo JsonConverter no va a funcionar. - BornToCode

¿Podrías responderme? Yongqiang Chen

"Json.NET es el serializador que ASP.NET usa por defecto" - Esto no era cierto cuando se hizo o respondió la pregunta. (pero lo más importante es la claridad de la respuesta) - Ryanwebjackson

He encontrado que Json.NET proporciona la funcionalidad exacta que estoy buscando con un StringEnumConverter atributo:

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

[JsonConverter(typeof(StringEnumConverter))]
public Gender Gender { get; set; }

Más detalles en disponible en StringEnumConverter documentación.

Hay otros lugares para configurar este convertidor de manera más global:

  • enum en sí mismo si desea que enum siempre se serialice / deserialice como cadena:

    [JsonConverter(typeof(StringEnumConverter))]  
    enum Gender { Male, Female }
    
  • En caso de que alguien quiera evitar la decoración de atributos, puede agregar el convertidor a su JsonSerializer (sugerido por Bjorn Egil):

    serializer.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); 
    

    y funcionará para cada enumeración que vea durante esa serialización (sugerida por Travis).

  • o JsonConverter (sugerido por plátano):

    JsonConvert.SerializeObject(MyObject, 
        new Newtonsoft.Json.Converters.StringEnumConverter());
    

Además, puede controlar el uso de mayúsculas y minúsculas y si los números aún se aceptan utilizando StringEnumConverter (NamingStrategy, Boolean) constructor.

Respondido el 25 de Septiembre de 19 a las 22:09

Siga el enlace para obtener una descripción de cómo usarlo en la aplicación asp.net mvc james.newtonking.com/archive/2008/10/16/… - rredcat

Aquí está el enlace a esa función: james.newtonking.com/projects/json/help/html/… - Tipo CAD

HttpConfiguration config = GlobalConfiguration.Configuration; config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; config.Formatters.JsonFormatter.SerializerSettings.Converters.Add (new Newtonsoft.Json.Converters.StringEnumConverter ()); - Iggy

Es útil tener en cuenta que, por defecto, ASP.NET MVC no usa Json.Net como serializador json y es necesario extender Controller o anular manualmente cada serialización. - odys

Puede personalizar el convertidor (por ejemplo, para camelCase producción): new StringEnumConverter { CamelCaseText = true } - Pescado de mar

Agregue lo siguiente a su global.asax para la serialización JSON de c # enum como cadena

  HttpConfiguration config = GlobalConfiguration.Configuration;
            config.Formatters.JsonFormatter.SerializerSettings.Formatting =
                Newtonsoft.Json.Formatting.Indented;

            config.Formatters.JsonFormatter.SerializerSettings.Converters.Add
                (new Newtonsoft.Json.Converters.StringEnumConverter());

Respondido 09 ago 13, 19:08

Por alguna razón, no estoy logrando que esto funcione. Fiddler muestra un 2 terco en lugar de 'Advertencia', incluso con esto en su lugar. Además, cualquier motivo para cambiar el Formatting a Indented? - sq33G

La tercera línea de este ejemplo se agregó al archivo App_start / webapiconfig.cs y me hizo un truco en un proyecto ASP.NET Web API 2.1 para devolver cadenas para valores de enumeración en llamadas REST (json fomat). - greg z

¿Hay alguna forma de establecer esta propiedad solo por el alcance de la solicitud? - Anestis Kivranoglou

@AnestisKivranoglou solo usa un serializador json personalizado por solicitud con su propia configuración. - BrainSlugs83

la primera configuración de serializador de sangría no está relacionada con la pregunta op. - user3791372

@Iggy answer establece la serialización JSON de c # enum como una cadena solo para ASP.NET (API web, etc.).

Pero para que funcione también con la serialización ad hoc, agregue lo siguiente a su clase de inicio (como Global.asax Application_Start)

//convert Enums to Strings (instead of Integer) globally
JsonConvert.DefaultSettings = (() =>
{
    var settings = new JsonSerializerSettings();
    settings.Converters.Add(new StringEnumConverter { CamelCaseText = true });
    return settings;
});

Más información en la página Json.NET

Además, para que su miembro enum serialice / deserialice hacia / desde un texto específico, use el

System.Runtime.Serialization.EnumMember

atributo, como este:

public enum time_zone_enum
{
    [EnumMember(Value = "Europe/London")] 
    EuropeLondon,

    [EnumMember(Value = "US/Alaska")] 
    USAlaska
}

respondido 24 nov., 14:11

¡Gracias! Solo estaba buscando [EnumMember]. - Poulad

La CamelCaseText la propiedad ahora está marcada como obsoleta. Nueva forma de instanciar el convertidor: new StringEnumConverter(new CamelCaseNamingStrategy()) - hágase

Muchas gracias, me alegró el día! :) - Eldoïr

el JsonConvert que coloca en ConfigureServices o en Configure en NET CORE 2? - desarrollador learn999

No pude cambiar el modelo de origen como en la respuesta principal (de @ob.), Y no quería registrarlo globalmente como @Iggy. Así que combiné https://stackoverflow.com/a/2870420/237091 y @ Iggy https://stackoverflow.com/a/18152942/237091 para permitir la configuración del convertidor de enumeración de cadenas durante el comando SerializeObject en sí:

Newtonsoft.Json.JsonConvert.SerializeObject(
    objectToSerialize, 
    Newtonsoft.Json.Formatting.None, 
    new Newtonsoft.Json.JsonSerializerSettings()
    {
        Converters = new List<Newtonsoft.Json.JsonConverter> {
            new Newtonsoft.Json.Converters.StringEnumConverter()
        }
    })

contestado el 23 de mayo de 17 a las 12:05

esto también funciona bien si tiene una propiedad como esta Lista - Bogdan

Como mencionó @Bogdan, esta fue la solución para que yo hiciera un List<AnEnumType> propiedad serializar con el valor de cadena de cada valor Enum en lugar del valor numérico. - Juan Washam

La combinación de las respuestas de Omer Bokhari y uri es siempre mi solución, ya que los valores que quiero proporcionar suelen ser diferentes de los que tengo en mi enumeración, especialmente porque me gustaría poder cambiar mis enumeraciones si es necesario.

Entonces, si alguien está interesado, es algo como esto:

public enum Gender
{
   [EnumMember(Value = "male")] 
   Male,
   [EnumMember(Value = "female")] 
   Female
}

class Person
{
    int Age { get; set; }
    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}

Respondido 16 ago 17, 11:08

Estaba usando JsonPropertyAttribute para miembros de enumeración y funciona para tareas de deserialización simples. Lamentablemente, durante los ajustes manuales con JTokens se ignora. Felizmente EnumMemberAttribute Funciona de maravilla. ¡Gracias! - Prólogo

Esto se hace fácilmente agregando un ScriptIgnore atribuir a la Gender propiedad, lo que hace que no se serialice y agregue un GenderString propiedad que ser serializado:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

    string GenderString { get { return Gender.ToString(); } }
}

Respondido 21 Feb 18, 13:02

Déjame intentar explicar. Esta solución no es correcta según los paters de diseño. Modificó el modelo de acuerdo con el propósito de la vista. Pero el modelo solo tiene que contener datos y no se preocupan por las presentaciones. Tienes que mover esta funcionalidad a la otra capa. - rredcat

En realidad, Model se usa para pasar datos del controlador, y es el controlador, al que no le importa la presentación. La introducción de la propiedad automatizada (GenderString aquí) no interrumpe el controlador, que todavía usa la propiedad de género, pero proporciona un acceso fácil para una vista. Solución lógica. - Dima

@RredCat No hay nada de malo en tener propiedades específicas de vista en el "modelo de vista". En mi humilde opinión, el error sería no dividir el modelo de vista del modelo de dominio: blogs.msdn.com/b/simonince/archive/2010/01/26/… - mariano desanze

@RredCat, incluso si fuera incorrecto de acuerdo con algún patrón, el OP no dice nada al respecto, por lo que esta es una respuesta correcta. (Incluso si filosóficamente estoy de acuerdo con tu punto). MEMARCA

El desprendimiento de bicicletas pedante y absurdo en este hilo de comentarios es fascinante. - mike mooney

Forma de ASP.NET Core:

public class Startup
{
  public IServiceProvider ConfigureServices(IServiceCollection services)
  {
    services.AddMvc().AddJsonOptions(options =>
    {
      options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
    });
  }
}

https://gist.github.com/regisdiogo/27f62ef83a804668eb0d9d0f63989e3e

Respondido el 19 de junio de 18 a las 09:06

Esta versión de Stephen https://www.youtube.com/watch?v=xB-eutXNUMXJtA&feature=youtu.be no cambia el nombre en el JSON:

[DataContract(
    Namespace = 
       "http://schemas.datacontract.org/2004/07/Whatever")]
class Person
{
    [DataMember]
    int Age { get; set; }

    Gender Gender { get; set; }

    [DataMember(Name = "Gender")]
    string GenderString
    {
        get { return this.Gender.ToString(); }
        set 
        { 
            Gender g; 
            this.Gender = Enum.TryParse(value, true, out g) ? g : Gender.Male; 
        }
    }
}

contestado el 23 de mayo de 17 a las 12:05

Creo que esto es válido para el DataContractJsonSerializer no JavaScriptSerializer - KCD

Simple y me resuelve el problema usando serializadores nativos de .NET Framework. - El senador

la mejor solución para mí, ya que no puedo usar bibliotecas de terceros (problemas de cumplimiento de ISO) - Daniel Gruszczyk

Por supuesto, esto no es para el tipo de serializador en cuestión. JavaScriptSerializer serializa todo lo que no se ignora, mientras que DataContractJsonSerializer requiere atributos DataMember. Gracias por el saludo, pero tenga en cuenta que ha escrito mal mi nombre :) - Stephen Kennedy

Aquí está la respuesta para newtonsoft.json

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}

Respondido 21 Abr '15, 10:04

Gracias por esta respuesta, ¡me ayudó mucho! Si desea definir sus enumeraciones en PascalCase, pero desea que se serialice en camelCase, debe agregar true a su tipo JsonConverter de esta manera: [JsonConverter(typeof(StringEnumConverter), true)] - Peet

En .net core 3 esto ahora es posible con las clases integradas en System.Text.Json (editar: System.Text.Json también está disponible como paquete NuGet para .net core 2.0 y .net framework 4.7.2 y versiones posteriores de acuerdo con la documentos):

var person = new Person();
// Create and add a converter which will use the string representation instead of the numeric value.
var stringEnumConverter = new System.Text.Json.Serialization.JsonStringEnumConverter();
JsonSerializerOptions opts = new JsonSerializerOptions();
opts.Converters.Add(stringEnumConverter);
// Generate json string.
var json = JsonSerializer.Serialize<Person>(person, opts);

Para configurar JsonStringEnumConverter con decoración de atributos para la propiedad específica:

using System.Text.Json.Serialization;

[JsonConverter(typeof(JsonStringEnumConverter))]
public Gender Gender { get; set; }

Si desea convertir siempre la enumeración como cadena, coloque el atributo en la enumeración.

[JsonConverter(typeof(JsonStringEnumConverter))] 
enum Gender { Male, Female }

Respondido el 14 de Septiembre de 20 a las 13:09

También puede agregar un convertidor a su JsonSerializer si no quieres usar JsonConverter atributo:

string SerializedResponse = JsonConvert.SerializeObject(
     objToSerialize, 
     new Newtonsoft.Json.Converters.StringEnumConverter()
); 

Funcionará para todos enum ve durante esa serialización.

Respondido 13 Jul 16, 14:07

Asp.Net Core 3 con System.Text.Json

public void ConfigureServices(IServiceCollection services)
{

    services
        .AddControllers()
        .AddJsonOptions(options => 
           options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())
        );

    //...
 }

respondido 11 nov., 19:00

Aquí hay una solución simple que serializa una enumeración C # del lado del servidor en JSON y usa el resultado para completar una enumeración del lado del cliente <select> elemento. Esto funciona tanto para enumeraciones simples como para enumeraciones bitflag.

He incluido la solución de extremo a extremo porque creo que la mayoría de las personas que desean serializar una enumeración de C # en JSON probablemente también la usarán para completar una <select> desplegable.

Aquí va:

Ejemplo de enumeración

public enum Role
{
    None = Permission.None,
    Guest = Permission.Browse,
    Reader = Permission.Browse| Permission.Help ,
    Manager = Permission.Browse | Permission.Help | Permission.Customise
}

Una enumeración compleja que utiliza OR bit a bit para generar un sistema de permisos. Entonces no puede confiar en el índice simple [0,1,2 ..] para el valor entero de la enumeración.

Lado del servidor: C #

Get["/roles"] = _ =>
{
    var type = typeof(Role);
    var data = Enum
        .GetNames(type)
        .Select(name => new 
            {
                Id = (int)Enum.Parse(type, name), 
                Name = name 
            })
        .ToArray();

    return Response.AsJson(data);
};

El código anterior usa el marco NancyFX para manejar la solicitud Get. Utiliza el de Nancy Response.AsJson() método auxiliar, pero no se preocupe, puede usar cualquier formateador JSON estándar, ya que la enumeración ya se ha proyectado en un tipo anónimo simple listo para la serialización.

JSON generado

[
    {"Id":0,"Name":"None"},
    {"Id":2097155,"Name":"Guest"},
    {"Id":2916367,"Name":"Reader"},
    {"Id":4186095,"Name":"Manager"}
]

Lado del cliente - CoffeeScript

fillSelect=(id, url, selectedValue=0)->
    $select = $ id
    $option = (item)-> $ "<option/>", 
        {
            value:"#{item.Id}"
            html:"#{item.Name}"
            selected:"selected" if item.Id is selectedValue
        }
    $.getJSON(url).done (data)->$option(item).appendTo $select for item in data

$ ->
    fillSelect "#role", "/roles", 2916367

HTML antes

<select id="role" name="role"></select>

HTML después

<select id="role" name="role">
    <option value="0">None</option>
    <option value="2097155">Guest</option>
    <option value="2916367" selected="selected">Reader</option>
    <option value="4186095">Manager</option>
</select>

Respondido el 22 de Septiembre de 14 a las 15:09

Para ASP.Net core Simplemente agregue lo siguiente a su Clase de inicio:

JsonConvert.DefaultSettings = (() =>
        {
            var settings = new JsonSerializerSettings();
            settings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
            return settings;
        });

Respondido 17 Oct 18, 06:10

Puede crear JsonSerializerSettings con la llamada a JsonConverter.SerializeObject como se muestra a continuación:

var result = JsonConvert.SerializeObject
            (
                dataObject,
                new JsonSerializerSettings
                {
                    Converters = new [] {new StringEnumConverter()}
                }
            );

Respondido el 17 de junio de 15 a las 13:06

Se dio cuenta de que no hay respuesta para la serialización cuando hay un atributo Descripción.

Aquí está mi implementación que admite el atributo Descripción.

public class CustomStringEnumConverter : Newtonsoft.Json.Converters.StringEnumConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Type type = value.GetType() as Type;

        if (!type.IsEnum) throw new InvalidOperationException("Only type Enum is supported");
        foreach (var field in type.GetFields())
        {
            if (field.Name == value.ToString())
            {
                var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
                writer.WriteValue(attribute != null ? attribute.Description : field.Name);

                return;
            }
        }

        throw new ArgumentException("Enum not found");
    }
}

enumeración:

public enum FooEnum
{
    // Will be serialized as "Not Applicable"
    [Description("Not Applicable")]
    NotApplicable,

    // Will be serialized as "Applicable"
    Applicable
}

Uso:

[JsonConverter(typeof(CustomStringEnumConverter))]
public FooEnum test { get; set; }

respondido 05 mar '16, 08:03

Para .Net Core: -

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
    ...
}

Respondido el 04 de Septiembre de 19 a las 22:09

Si este es el de la Microsoft.AspNetCore.Mvc.Formatters.Json Paquete NuGet, parece ser solo un método de extensión en IMvcCoreBuilderno, IMvcBuilder. Entonces se usa como services.AddMvcCore().AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));. - infl3x

En caso de que alguien considere que lo anterior es insuficiente, terminé conformándome con esta sobrecarga:

JsonConvert.SerializeObject(objToSerialize, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())

Respondido el 27 de junio de 16 a las 09:06

Esta es una buena solución para un caso de uso actual mío: no quiero cambiar los valores predeterminados de los serializadores y tengo problemas para usar atributos, porque mis propiedades son de tipo IList . - dirk brockhaus

Esta es una vieja pregunta, pero pensé en contribuir por si acaso. En mis proyectos, uso modelos separados para cualquier solicitud de Json. Un modelo normalmente tendría el mismo nombre que el objeto de dominio con el prefijo "Json". Los modelos se mapean usando AutoMapper. Al hacer que el modelo json declare una propiedad de cadena que es una enumeración en la clase de dominio, AutoMapper resolverá su presentación de cadena.

En caso de que se lo pregunte, necesito modelos separados para las clases serializadas de Json porque, de lo contrario, el serializador incorporado tiene referencias circulares.

Espero que esto ayude a alguien.

respondido 27 mar '12, 16:03

Es bueno saber que la característica de Automapper ;-) El atributo [ScriptIgnore] eliminará las referencias circulares - dragón led

Oh. No sabía nada del atributo. ¡Gracias! ¿Usarías eso en tus Pocos? He recurrido al uso de definiciones de MetadataType para cualquier atributo de Poco solo para mantenerlos limpios. ¿Seguiría funcionando el atributo a través de metadatos? - Ales Potocnik Hahonina

De hecho, puede usar un JavaScriptConverter para lograr esto con el JavaScriptSerializer incorporado. Al convertir su enumeración en un Uri, puede codificarlo como una cadena.

Describí cómo hacer esto para las fechas, pero también se puede usar para enumeraciones. Formato JSON de fecha y hora personalizado para .NET JavaScriptSerializer.

Respondido 19 ago 19, 14:08

¡Solución muy interesante! Gracias por compartir. - Oliver

No estoy seguro de si esto sigue siendo relevante, pero tuve que escribir directamente en un archivo json y se me ocurrió lo siguiente juntando varias respuestas de stackoverflow.

public class LowercaseJsonSerializer
{
    private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        ContractResolver = new LowercaseContractResolver()
    };

    public static void Serialize(TextWriter file, object o)
    {
        JsonSerializer serializer = new JsonSerializer()
        {
            ContractResolver = new LowercaseContractResolver(),
            Formatting = Formatting.Indented,
            NullValueHandling = NullValueHandling.Ignore
        };
        serializer.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
        serializer.Serialize(file, o);
    }

    public class LowercaseContractResolver : DefaultContractResolver
    {
        protected override string ResolvePropertyName(string propertyName)
        {
            return Char.ToLowerInvariant(propertyName[0]) + propertyName.Substring(1);
        }
    }
}

Asegura que todas mis claves json están en minúsculas comenzando de acuerdo con las "reglas" de json. Formatea con sangría limpia e ignora los nulos en la salida. Además, al agregar un StringEnumConverter, imprime enumeraciones con su valor de cadena.

Personalmente, encuentro que esto es lo más limpio que se me ocurrió, sin tener que ensuciar el modelo con anotaciones.

uso:

    internal void SaveJson(string fileName)
    {
        // serialize JSON directly to a file
        using (StreamWriter file = File.CreateText(@fileName))
        {
            LowercaseJsonSerializer.Serialize(file, jsonobject);
        }
    }

Respondido el 19 de diciembre de 18 a las 08:12

Y para VB.net encontré los siguientes trabajos:

Dim sec = New Newtonsoft.Json.Converters.StringEnumConverter()
sec.NamingStrategy() = New Serialization.CamelCaseNamingStrategy

Dim JSON_s As New JsonSerializer
JSON_s.Converters.Add(sec)

Dim jsonObject As JObject
jsonObject = JObject.FromObject(SomeObject, JSON_s)
Dim text = jsonObject.ToString

IO.File.WriteAllText(filePath, text)

contestado el 15 de mayo de 19 a las 22:05

He reunido todas las piezas de esta solución usando el Newtonsoft.Json Biblioteca. Soluciona el problema de la enumeración y también hace que el manejo de errores sea mucho mejor, y funciona en servicios alojados en IIS. Es bastante código, por lo que puede encontrarlo en GitHub aquí: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs

Tienes que agregar algunas entradas a tu Web.config para que funcione, puede ver un archivo de ejemplo aquí: https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config

Respondido 12 Jul 16, 11:07

Una opción un poco más preparada para el futuro

Ante la misma pregunta, determinamos que necesitábamos una versión personalizada de StringEnumConverter para asegurarnos de que nuestros valores de enumeración puedan expandirse con el tiempo sin romperse catastróficamente en el lado de la deserialización (consulte los antecedentes a continuación). Utilizando la SafeEnumConverter a continuación permite que finalice la deserialización incluso si la carga útil contiene un valor para la enumeración que no tiene una definición con nombre, más cerca de cómo funcionaría la conversión de int-a-enum.

Uso:

[SafeEnumConverter]
public enum Colors
{
    Red,
    Green,
    Blue,
    Unsupported = -1
}

or

[SafeEnumConverter((int) Colors.Blue)]
public enum Colors
{
    Red,
    Green,
    Blue
}

Fuente:

public class SafeEnumConverter : StringEnumConverter
{
    private readonly int _defaultValue;

    public SafeEnumConverter()
    {
        // if you've been careful to *always* create enums with `0` reserved
        // as an unknown/default value (which you should), you could use 0 here. 
        _defaultValue = -1;
    }

    public SafeEnumConverter(int defaultValue)
    {
        _defaultValue = defaultValue;
    }

    /// <summary>
    /// Reads the provided JSON and attempts to convert using StringEnumConverter. If that fails set the value to the default value.
    /// </summary>
    /// <returns>The deserialized value of the enum if it exists or the default value if it does not.</returns>
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            return base.ReadJson(reader, objectType, existingValue, serializer);
        }
        catch
        {
            return Enum.Parse(objectType, $"{_defaultValue}");
        }
    }

    public override bool CanConvert(Type objectType)
    {
        return base.CanConvert(objectType) && objectType.GetTypeInfo().IsEnum;
    }
}

Antecedentes

Cuando miramos el uso de StringEnumConverter, el problema que teníamos es que también necesitábamos pasividad para los casos en los que se agregaba un nuevo valor de enumeración, pero no todos los clientes eran conscientes de inmediato del nuevo valor. En estos casos, el StringEnumConverter empaquetado con Newtonsoft JSON arroja un JsonSerializationException similar a "Error al convertir el valor SomeString para escribir EnumType" y luego el todo El proceso de deserialización falla. Esto fue un factor decisivo para nosotros, porque incluso si el cliente planeaba ignorar / descartar el valor de la propiedad que no entendía, ¡aún tenía que ser capaz de deserializar el resto de la carga útil!

Respondido 06 ago 19, 19:08

Todavía es relativamente nuevo en .NET, pero me han dicho que evite las expresiones de captura de prueba por razones de rendimiento. ¿No sería un serializador un mal lugar para usar uno si ese es el caso? - laventnc

@laventnc El try ... catch en sí mismo no afectará el rendimiento, pero si se genera una excepción, hay una sobrecarga de rendimiento para eso. El objetivo de esta implementación es la tolerancia a fallas ... no permitir que un solo valor de enumeración desconocido evite que se deserialice toda la carga útil JSON. Compara la base StringEnumConveter: la excepción aún se generaría, pero hará que todo el proceso de deserialización falle (y es probable que quede atrapado en algún lugar más arriba de la pila). Si necesita este tipo de tolerancia a fallas es un artefacto de su (s) caso (s) de uso. - Polvoriento

        Person p = new Person();
        p.Age = 35;
        p.Gender = Gender.Male;
        //1.  male="Male";
        string male = Gender.Male.ToString();

        p.Gender = Gender.Female;

        //2.  female="Female";
        string female = Enum.GetName(typeof(Gender), p.Gender);

        JObject jobj = new JObject();
        jobj["Age"] = p.Age;
        jobj["Gender"] = male;
        jobj["Gender2"] = female;

        //you result:  josn= {"Age": 35,"Gender": "Male","Gender2": "Female"}
        string json = jobj.ToString();

Respondido el 26 de diciembre de 19 a las 03:12

new JavaScriptSerializer().Serialize(  
    (from p   
    in (new List<Person>() {  
        new Person()  
        {  
            Age = 35,  
            Gender = Gender.Male  
        }  
    })  
    select new { Age =p.Age, Gender=p.Gender.ToString() }  
    ).ToArray()[0]  
);

Respondido 19 Abr '16, 16:04

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.