JavaScriptSerializer: serialización JSON de enum como cadena

1162

Tengo una clase que contiene una enumpropiedad, 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 manera de obtener la enumeración como a stringen mi json sin tener que crear una costumbre JavaScriptConverter? ¿Quizás hay un atributo con el que podría decorar la enumdefinición o propiedad del objeto?

Como ejemplo:

enum Gender { Male, Female }

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

Resultado json deseado:

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

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

Omer Bokhari
fuente
8
¿Cambiar a cuál? La respuesta más votada en realidad 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 el MS JavaScriptSerializer, como lo es esencialmente 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 pirateo hace el trabajo.
Stephen Kennedy

Respuestas:

376

No, no hay ningún atributo especial que pueda usar. JavaScriptSerializerserializa enumsa sus valores numéricos y no a su representación de cadena. Tendría que usar la serialización personalizada para serializar enumcomo su nombre en lugar de su valor numérico.


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

Matt Dearing
fuente
77
@Fabzter: su solución funcionó conmigo usando Json de Newtonsoft
BeemerGuy
1
@BornToCode Json.NET es el serializador que ASP.NET usa de manera predeterminada.
BrainSlugs83
12
@ BrainSlugs83: la pregunta era sobre el uso de JavaScriptSerializer, no Json.NET (y si mira el historial de revisiones verá que hubo una edición para aclarar eso), si usa JavaScriptSerializer, el atributo JsonConverterno funcionará.
BornToCode
50
Elimine esto como la respuesta aceptada, ya que no resuelve el problema, la respuesta a continuación con más de 1000 votos positivos sí.
MHGameWork
podrías responderme
Yongqiang Chen
2101

Descubrí que Json.NET proporciona la funcionalidad exacta que busco con un StringEnumConverteratributo:

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

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

Más detalles disponibles en la StringEnumConverterdocumentación .

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

  • enum si quieres 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 Bjørn Egil ):

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

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

  • o JsonConverter (sugerido por banana ):

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

Además, puede controlar la carcasa y si los números aún se aceptan utilizando el constructor StringEnumConverter (NamingStrategy, Boolean) .

Omer Bokhari
fuente
99
Siga por 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
2
Aquí está el enlace a esa función: james.newtonking.com/projects/json/help/html/…
CAD
61
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
1
Es útil tener en cuenta de forma predeterminada que ASP.NET MVC no utiliza Json.Net como serializador json y es necesario extender Controllero anular manualmente cada serialización.
Odys
2
Puede personalizar el convertidor (por ejemplo, para la camelCasesalida):new StringEnumConverter { CamelCaseText = true }
Seafish
172

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());
Iggy
fuente
44
Por alguna razón, no estoy haciendo que esto funcione. Fiddler muestra un terco 2 en lugar de 'Advertencia', incluso con esto en su lugar. Además, ¿alguna razón por la que cambiar el Formattinga Indented?
sq33G
55
La tercera línea de este ejemplo se agregó al archivo App_start / webapiconfig.cs e hizo un truco para mí en un proyecto ASP.NET Web API 2.1 para devolver cadenas de valores de enumeración en llamadas REST (json fomat).
Greg Z.
1
¿Hay alguna forma de establecer esta propiedad solo por ámbito de solicitud?
Anestis Kivranoglou
@AnestisKivranoglou solo utiliza un serializador json personalizado por solicitud con su propia configuración.
BrainSlugs83
3
la primera configuración de serializador de sangrado no está relacionada con la pregunta operativa.
user3791372
153

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

Pero para que funcione también con la serialización ad hoc, agregue 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 de Json.NET

Además, para que su miembro de enumeración serialice / deserialice a / de 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
}
Juri
fuente
66
¡Gracias! Solo estaba buscando [EnumMember].
Poulad
La CamelCaseTextpropiedad ahora está marcada como obsoleta. Nueva forma de instanciar el convertidor:new StringEnumConverter(new CamelCaseNamingStrategy())
fiat
Muchas gracias, me alegraron el día! :)
Eldoïr
39

No pude cambiar el modelo de origen como en la respuesta superior (de @ob.), Y no quería registrarlo globalmente como @Iggy. Por lo que combinado https://stackoverflow.com/a/2870420/237091 y @ de Iggy https://stackoverflow.com/a/18152942/237091 para permitir la creación de la cadena de convertidor de enumeración durante el propio comando SerializeObject:

Newtonsoft.Json.JsonConvert.SerializeObject(
    objectToSerialize, 
    Newtonsoft.Json.Formatting.None, 
    new Newtonsoft.Json.JsonSerializerSettings()
    {
        Converters = new List<Newtonsoft.Json.JsonConverter> {
            new Newtonsoft.Json.Converters.StringEnumConverter()
        }
    })
Scott Stafford
fuente
esto también funciona bien si tiene una propiedad como esta List <someEnumType>
Bogdan
34

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 que me gustaría poder cambiar mis enumeraciones si fuera 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; }
}
Ashkan Sirous
fuente
1
Estaba usando JsonPropertyAttributepara miembros de enumeración y está trabajando para tareas de deserialización simples. Lamentablemente, durante los ajustes manuales con JTokens se ignora. Happilly EnumMemberAttributefunciona a las mil maravillas . ¡Gracias!
Prolog
Eso funciona con JavaScriptSerializer?
Stephen Kennedy el
31

Esto se hace fácilmente mediante la adición de un ScriptIgnoreatributo a la Genderpropiedad, haciendo que no se puede serializar, y añadiendo una GenderStringpropiedad que no conseguir serializado:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

    string GenderString { get { return Gender.ToString(); } }
}
Stephen Kennedy
fuente
29
Déjame intentar explicar. Esta solución no es correcta según los patrones de diseño. Modificó el modelo según el propósito de la vista. Pero el modelo solo debe contener datos y no le importan las presentaciones. Tienes que mover esta funcionalidad a la otra capa.
RredCat
44
En realidad, el Modelo se usa para pasar datos del controlador, y es el controlador, a quien 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 Gender, pero proporciona un fácil acceso para una vista. Solución lógica
Dima
17
@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
55
@RredCat, incluso si fuera incorrecto según algún patrón, el OP no dice nada al respecto, por lo que esta es una respuesta correcta. (Incluso si filosóficamente puedo estar de acuerdo con su punto.)
MEMark
10
El derramamiento de bicicletas pedante y absurdo en este hilo de comentarios es fascinante.
Mike Mooney
26

Esta versión de la respuesta de Stephen 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; 
        }
    }
}
mheyman
fuente
3
Creo que esto es válido para el DataContractJsonSerializernoJavaScriptSerializer
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
Esto no es para el tipo de serializador en la pregunta, por supuesto. JavaScriptSerializer serializa todo lo que no se ignora, mientras que DataContractJsonSerializer requiere atributos DataMember. Gracias por el grito hacia fuera, pero tenga en cuenta de que ha escrito mal mi nombre :)
Stephen Kennedy
25

Aquí está la respuesta para newtonsoft.json

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}
GuCa
fuente
1
Gracias por esta respuesta, me ayudó mucho! Si desea definir sus enumeraciones en PascalCase, pero desea que se serialice en camelCase, debe agregar truea su tipo JsonConverter de esta manera:[JsonConverter(typeof(StringEnumConverter), true)]
Peet
25

ASP.NET Core way:

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

st1
fuente
funciona perfectamente
DevJoe
16

También puede agregar un convertidor a su JsonSerializersi no desea utilizar el JsonConverteratributo:

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

Funcionará para todo enumlo que vea durante esa serialización.

JerryGoyal
fuente
15

Aquí hay una solución simple que serializa una enumeración de C # del lado del servidor a JSON y utiliza el resultado para completar un <select>elemento del lado del cliente . Esto funciona tanto para enumeraciones simples como para enumeraciones de 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 # a JSON probablemente también la usarán para completar un <select>menú 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. Por lo tanto, 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 Response.AsJson()método auxiliar de Nancy, 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>
biofractal
fuente
13

Para ASP.Net core Solo agregue lo siguiente a su clase de inicio:

JsonConvert.DefaultSettings = (() =>
        {
            var settings = new JsonSerializerSettings();
            settings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
            return settings;
        });
Yahya Hussein
fuente
1
Esto funciona para todas las versiones, no solo para el núcleo.
bikeman868
11

Puede crear JsonSerializerSettings con la llamada a JsonConverter.SerializeObject de la siguiente manera:

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

Notó 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");
    }
}

Enum:

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; }
Greg R Taylor
fuente
10

Para .Net Core: -

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
    ...
}
PeteGO
fuente
2
Si este es el del Microsoft.AspNetCore.Mvc.Formatters.Jsonpaquete NuGet, parece ser solo un método de extensión activado IMvcCoreBuilder, no IMvcBuilder. Entonces se usa como services.AddMvcCore().AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));.
infl3x
9

En .net core 3 esto ahora es posible con las clases integradas en System.Text.Json:

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 JsonStringEnumConvertercon 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 misma.

[JsonConverter(typeof(JsonStringEnumConverter))] 
enum Gender { Male, Female }
Björn
fuente
9

Asp.Net Core 3 con System.Text.Json

public void ConfigureServices(IServiceCollection services)
{

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

    //...
 }
Serj-Tm
fuente
8

En caso de que alguien encuentre lo anterior insuficiente, terminé resolviéndome con esta sobrecarga:

JsonConvert.SerializeObject(objToSerialize, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())
hngr18
fuente
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 los atributos, porque mis propiedades son de tipo IList <EnumType>.
Dirk Brockhaus
5

Esta es una vieja pregunta, pero pensé que contribuiría 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 asignan 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 pregunte, necesito modelos separados para las clases serializadas de Json porque el serializador incorporado viene con referencias circulares de lo contrario.

Espero que esto ayude a alguien.

Ales Potocnik Hahonina
fuente
Es bueno aprender que la característica de Automapper ;-) [ScriptIgnore] eliminará las referencias circulares
ledragon
1
Oh. No sabía sobre el atributo. ¡Gracias! ¿Usarías eso en tu 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
3

En realidad, puede usar un convertidor de JavaScript 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 .

Sebastian Markbåge
fuente
¡Una solución muy interesante! Gracias por compartir.
Oliver
1

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

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" json. Da formato a una sangría limpia e ignora los nulos en la salida. Además, al agregar un StringEnumConverter, imprime enumeraciones con su valor de cadena.

Personalmente, creo que 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);
        }
    }
kenny
fuente
0

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

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

Jon Grant
fuente
0

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)
Benjamin Swedlove
fuente
0

Una opción un poco más a prueba de futuro

Enfrentando la misma pregunta, determinamos que necesitábamos una versión personalizada de StringEnumConverterpara asegurarnos de que nuestros valores de enumeración podrían expandirse con el tiempo sin romperse catastróficamente en el lado de deserialización (ver el fondo a continuación). Utilizando elSafeEnumConverter siguiente 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 enumeración.

Uso:

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

o

[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 analizamos el uso de StringEnumConverter, el problema que tuvimos fue que también necesitábamos pasividad para los casos en que se agregaba un nuevo valor de enumeración, pero no todos los clientes se daban cuenta de inmediato del nuevo valor. En estos casos, el StringEnumConverterpaquete con Newtonsoft JSON arroja un valor JsonSerializationExceptionsimilar a "Error al convertir el valor SomeString para escribir EnumType" y luego falla todo el proceso de deserialización. Esto fue un factor decisivo para nosotros, porque incluso si el cliente planeaba ignorar / descartar el valor de la propiedad que no entendía, ¡todavía tenía que ser capaz de deserializar el resto de la carga útil!

Polvoriento
fuente
-2
        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();
zilong
fuente
-5
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]  
);
Slava
fuente