JavaScriptSerializer - serializacja JSON wyliczenia jako łańcucha


1160

Mam klasę, która zawiera enumwłaściwość, a po serializacji obiektu przy użyciu JavaScriptSerializermój wynik json zawiera wartość całkowitą wyliczenia, a nie jego string„nazwę”. Czy istnieje sposób, aby uzyskać wyliczenie jako stringw moim Jsonie bez konieczności tworzenia niestandardowego JavaScriptConverter? Być może istnieje atrybut, za pomocą którego mógłbym ozdobić enumdefinicję lub właściwość obiektu?

Jako przykład:

enum Gender { Male, Female }

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

Pożądany wynik JSON:

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

Idealnie szukając odpowiedzi z wbudowanymi klasami .NET, jeśli nie możliwe, mile widziane są alternatywy (takie jak Json.net).


8
Chcesz zmienić? Najwyżej oceniona odpowiedź nie odpowiada na pytanie - tak, jest przydatna w innych kontekstach, stąd głosy, ale nie ma praktycznego zastosowania, jeśli utkniesz z MS JavaScriptSerializer, ponieważ zasadniczo używasz metod strony i , co najważniejsze, zgodnie z wymaganiami pytania. Przyjęta odpowiedź mówi, że to niemożliwe. Moja odpowiedź podczas odrobiny włamania do pracy.
Stephen Kennedy

Odpowiedzi:


375

Nie, nie ma specjalnego atrybutu, którego można użyć. JavaScriptSerializerserializuje enumsdo ich wartości liczbowych, a nie ich reprezentacji ciągu. Aby serializować nazwę enumjako nazwę zamiast wartości liczbowej, należy użyć niestandardowej serializacji .


Jeśli możesz użyć JSON.Net zamiast JavaScriptSerializerzobaczyć odpowiedź na to pytanie dostarczone przez OmerBakhari : JSON.net obejmuje ten przypadek użycia (poprzez atrybut [JsonConverter(typeof(StringEnumConverter))]) i wiele innych nieobsługiwanych przez wbudowane serializatory .net. Oto link porównujący funkcje i funkcje serializatorów .


7
@Fabzter - Twoje rozwiązanie współpracowało ze mną przy użyciu Jsona Newtonsoft
BeemerGuy

1
@BornToCode Json.NET to serializator, którego domyślnie używa ASP.NET.
BrainSlugs83

12
@ BrainSlugs83 - Pytanie dotyczyło użycia JavaScriptSerializer, a nie Json.NET (a jeśli spojrzysz na historię zmian, zobaczysz, że była edycja, aby to wyjaśnić), jeśli używasz JavaScriptSerializer, atrybut JsonConverternie zadziała.
BornToCode,

50
Proszę usunąć to jako zaakceptowaną odpowiedź, ponieważ nie rozwiązuje to problemu, odpowiedź poniżej z ponad 1000 pozytywnych komentarzy TAK.
MHGameWork

czy mógłbyś mi odpowiedzieć
Yongqiang Chen

2100

Odkryłem, że Json.NET zapewnia dokładnie tę funkcjonalność, której szukam z StringEnumConverteratrybutem:

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

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

Więcej szczegółów dostępnych w StringEnumConverterdokumentacji .

Istnieją inne miejsca, w których można skonfigurować ten konwerter bardziej globalnie:

  • samo wyliczanie, jeśli chcesz, wyliczanie zawsze jest serializowane / deserializowane jako ciąg:

    [JsonConverter(typeof(StringEnumConverter))]  
    enum Gender { Male, Female }
  • Jeśli ktoś chce uniknąć dekorowania atrybutów, możesz dodać konwerter do JsonSerializer (sugerowany przez Bjørn Egil ):

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

    i będzie działać dla każdego wyliczenia, które zobaczy podczas tej serializacji (sugerowane przez Travisa ).

  • lub JsonConverter (sugerowany przez banana ):

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

Dodatkowo możesz kontrolować obudowę i to, czy liczby są nadal akceptowane za pomocą konstruktora StringEnumConverter (NamingStrategy, Boolean) .


9
Kliknij link, aby uzyskać opis, jak go używać w aplikacji asp.net mvc james.newtonking.com/archive/2008/10/16/…
RredCat


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

1
Warto zauważyć, że domyślnie ASP.NET MVC nie używa Json.Net jako serializatora json i należy rozszerzyć Controllerlub ręcznie zastąpić każdą serializację.
Odys

2
Możesz dostosować konwerter (powiedzmy, na camelCasewyjściu):new StringEnumConverter { CamelCaseText = true }
Seafish

172

Dodaj poniższy kod do pliku global.asax w celu uzyskania serializacji JSON enum c # jako łańcucha

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

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

4
Z jakiegoś powodu nie działam. Skrzypek pokazuje uparty 2 zamiast „Ostrzeżenie”, nawet jeśli jest na miejscu. Również - każdy powód, aby zmienić Formattingsię Indented?
sq33G

5
Trzecia linia z tego przykładu została dodana do pliku App_start / webapiconfig.cs i zrobiła dla mnie sztuczkę w projekcie ASP.NET Web API 2.1, aby zwrócić ciągi znaków wartości wyliczonych w wywołaniach REST (json fomat).
Greg Z.

1
Czy istnieje sposób na ustawienie tej właściwości tylko dla zakresu zapytania?
Anestis Kivranoglou

@AnestisKivranoglou wystarczy użyć niestandardowego serializatora json na żądanie z jego własnymi ustawieniami.
BrainSlugs83

3
pierwsze ustawienie serializatora wcięcia nie ma związku z pytaniem operacyjnym.
user3791372,

153

Odpowiedź @Iggy ustawia serializację JSON wyliczenia c # jako ciąg tylko dla ASP.NET (Web API i tak dalej).

Aby jednak działał również z serializacją ad hoc, dodaj następujące elementy do swojej klasy początkowej (np. 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;
});

Więcej informacji na stronie Json.NET

Dodatkowo, aby twój członek enum szeregował / deserializował do / z określonego tekstu, użyj

System.Runtime.Serialization.EnumMember

atrybut, taki jak ten:

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

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

6
Dziękuję Ci! Właśnie szukałem [EnumMember].
Poulad,

CamelCaseTextWłaściwość jest teraz oznaczone nieaktualne. Nowy sposób na utworzenie instancji konwertera:new StringEnumConverter(new CamelCaseNamingStrategy())
fiat

Dziękuję bardzo, sprawiłem, że mój dzień! :)
Eldoïr

39

Nie byłem w stanie zmienić modelu źródłowego jak w górnej odpowiedzi (@ob.) I nie chciałem go rejestrować globalnie jak @Iggy. Więc połączyłem https://stackoverflow.com/a/2870420/237091 i @ Iggy's https://stackoverflow.com/a/18152942/237091, aby umożliwić skonfigurowanie konwertera wyliczania ciągów podczas samej komendy 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()
        }
    })

to też jest fajne, jeśli masz właściwość taką jak List <someEnumType>
Bogdan

34

Kombinacja odpowiedzi Omera Bokhari i uri jest zawsze moim rozwiązaniem, ponieważ wartości, które chcę podać, zwykle różnią się od tych, które mam w swoim wyliczeniu, szczególnie że chciałbym móc zmienić moje wyliczenia, jeśli zajdzie taka potrzeba.

Jeśli więc ktoś jest zainteresowany, może to wyglądać mniej więcej tak:

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

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

1
Używałem JsonPropertyAttributedla członków enum i działa dla prostych zadań deserializtion. Niestety podczas ręcznych poprawek za pomocą JTokens jest ignorowany. Happilly EnumMemberAttributedziała jak urok. Dzięki!
Prolog

To działa z JavaScriptSerializer?
Stephen Kennedy,

31

Można to łatwo zrobić, dodając ScriptIgnoreatrybut do Genderwłaściwości, powodując, że nie jest ona serializowana, i dodając GenderStringwłaściwość, która jest serializowana:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

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

29
Pozwól mi spróbować wyjaśnić. To rozwiązanie nie jest poprawne według wzorców projektowych. Zmodyfikowałeś model zgodnie z celem widoku. Ale model musi zawierać tylko dane i nie przejmuje się prezentacjami. Musisz przenieść tę funkcjonalność na drugą warstwę.
RredCat 17.04.13

4
W rzeczywistości Model służy do przekazywania danych z kontrolera, a także kontrolera, który nie dba o prezentację. Wprowadzenie właściwości automatycznej (tutaj GenderString) nie psuje kontrolera, który nadal korzysta z właściwości Gender, ale zapewnia łatwy dostęp do widoku. Logiczne rozwiązanie.
Dima,

17
@RredCat Nie ma nic złego w posiadaniu właściwości specyficznych dla widoku w „modelu widoku”. IMHO błędem byłoby nie rozdzielić modelu widoku od modelu domeny: blogs.msdn.com/b/simonince/archive/2010/01/26/…
Mariano Desanze

5
@RredCat, nawet jeśli był niepoprawny według jakiegoś wzorca, OP nie mówi o tym, więc to jest rzeczywiście poprawna odpowiedź. (Nawet jeśli z filozoficznego punktu widzenia mogę się zgodzić z tym, o co ci chodzi).
PAMIĘTAJ

10
Pedantycznie absurdalne zrzucanie rowerów w tym komentarzu jest fascynujące.
Mike Mooney

26

Ta wersja Stefana odpowiedź nie zmienia nazwę w 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; 
        }
    }
}

3
Uważam, że dotyczy to DataContractJsonSerializernieJavaScriptSerializer
KCD

Proste i rozwiązuje problem za pomocą natywnych serializatorów .NET Framework.
Senator

najlepsze rozwiązanie dla mnie, ponieważ nie wolno mi używać bibliotek stron trzecich (problemy ze zgodnością ISO)
Daniel Gruszczyk

Oczywiście nie dotyczy to typu serializatora. JavaScriptSerializer serializuje wszystko, co nie jest ignorowane, podczas gdy DataContractJsonSerializer wymaga atrybutów DataMember. Dziękuję za krzyk, ale pamiętaj, że źle przeliterowałeś moje imię :)
Stephen Kennedy

25

Oto odpowiedź dla newtonsoft.json

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

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

1
Dziękuję za tę odpowiedź, bardzo mi pomogła! Jeśli chcesz zdefiniować swoje wyliczenia w PascalCase, ale chcesz, aby były one serializowane w camelCase, musisz dodać truedo swojego typu JsonConverter w następujący sposób:[JsonConverter(typeof(StringEnumConverter), true)]
Peet


16

Możesz także dodać konwerter, JsonSerializerjeśli nie chcesz używać JsonConverteratrybutu:

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

Będzie działać dla każdego, enumco zobaczy podczas tej serializacji.


15

Oto proste rozwiązanie, które serializuje wyliczenie C # po stronie serwera do JSON i wykorzystuje wynik do wypełnienia po stronie klienta <select> elementu po . Działa to zarówno dla prostych, jak i dla bitflagów.

Zawarłem kompleksowe rozwiązanie, ponieważ myślę, że większość osób chcących serializować wyliczenie C # do JSON również prawdopodobnie użyje go do wypełnienia listy <select>rozwijanej.

Tutaj idzie:

Przykład Enum

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

Złożony wyliczenie, które wykorzystuje bitowe OR do generowania systemu uprawnień. Dlatego nie można polegać na prostym indeksie [0,1,2 ..] dla wartości całkowitej wyliczenia.

Po stronie serwera - 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);
};

Powyższy kod używa struktury NancyFX do obsługi żądania Get. Wykorzystuje NancyResponse.AsJson() metodę pomocniczą - ale nie martw się, możesz użyć dowolnego standardowego formatyzatora JSON, ponieważ wyliczenie zostało już zaprojektowane w prosty anonimowy typ gotowy do serializacji.

Wygenerowano JSON

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

Strona klienta - 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 przed

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

HTML After

<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>

13

Dla rdzenia ASP.Net Po prostu dodaj następujące elementy do klasy startowej:

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

1
Działa to dla wszystkich wersji, nie tylko podstawowych.
bikeman868

11

Możesz utworzyć JsonSerializerSettings za pomocą wywołania JsonConverter.SerializeObject, jak poniżej:

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

10

Zauważyliśmy, że nie ma odpowiedzi na serializację, gdy istnieje atrybut Opis.

Oto moja implementacja, która obsługuje atrybut Opis.

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
}

Stosowanie:

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

10

Dla .Net Core: -

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

2
Jeśli jest to ten z Microsoft.AspNetCore.Mvc.Formatters.Jsonpakietu NuGet, wydaje się, że jest to tylko metoda rozszerzenia IMvcCoreBuilder, a nie IMvcBuilder. Więc jest używany jak services.AddMvcCore().AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));.
infl3x

9

W .net core 3 jest to teraz możliwe dzięki wbudowanym klasom w 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);

Aby skonfigurować JsonStringEnumConverterz dekoracją atrybutu dla określonej właściwości:

using System.Text.Json.Serialization;

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

Jeśli chcesz zawsze konwertować wyliczenie jako ciąg, umieść atrybut w samym wyliczeniu.

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

9

Asp.Net Core 3 z System.Text.Json

public void ConfigureServices(IServiceCollection services)
{

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

    //...
 }

8

Na wypadek, gdyby ktokolwiek uznał powyższe za niewystarczające, skończyłem z tym przeciążeniem:

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

To dobre rozwiązanie dla mojego obecnego przypadku użycia: nie chcę zmieniać ustawień domyślnych serializatorów i mam problemy z używaniem atrybutów, ponieważ moje właściwości są typu IList <EnumType>.
Dirk Brockhaus

5

To stare pytanie, ale pomyślałem, że na wszelki wypadek. W moich projektach używam osobnych modeli dla wszystkich żądań Json. Model zazwyczaj miałby taką samą nazwę jak obiekt domeny z prefiksem „Json”. Modele są mapowane za pomocą AutoMapper . Dzięki temu, że model json deklaruje właściwość ciągu będącą wyliczeniem klasy domeny, AutoMapper rozpoznaje prezentację ciągu.

Jeśli się zastanawiasz, potrzebuję osobnych modeli dla serializowanych klas Jsona, ponieważ wbudowany serializator zawiera odwołania cykliczne.

Mam nadzieję, że to komuś pomoże.


Miło jest poznać tę funkcję Automapper ;-) Atrybut [ScriptIgnore] usunie okrągłe odniesienia
ledragon

1
O. Nie wiedziałem o atrybucie. Dzięki! Czy użyłbyś tego na swoim Pocos? Użyłem definicji MetadataType dla dowolnych atrybutów Poco, aby utrzymać je w czystości. Czy atrybut nadal działałby za pośrednictwem metadanych?
Ales Potocnik Hahonina,


1

Nie jestem pewien, czy to nadal jest istotne, ale musiałem napisać prosto do pliku JSON i wymyśliłem następujący sposób składania kilku odpowiedzi przepełnienia stosu

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);
        }
    }
}

Zapewnia to, że wszystkie moje klucze json są pisane małymi literami, zgodnie z „regułami” json. Formatuje czyste wcięcie i ignoruje wartości zerowe w danych wyjściowych. Również dodając StringEnumConverter drukuje wyliczenia z ich wartością ciągu.

Osobiście uważam, że jest to najczystszy sposób, jaki mogłem wymyślić, bez konieczności brudzenia modelu adnotacjami.

stosowanie:

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

0

Złożyłem wszystkie elementy tego rozwiązania za pomocą Newtonsoft.Jsonbiblioteki. Rozwiązuje problem wyliczania, a także znacznie poprawia obsługę błędów i działa w usługach hostowanych w IIS. To całkiem sporo kodu, więc możesz go znaleźć na GitHub tutaj: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs

Musisz dodać kilka wpisów do swojego Web.config, aby działało, możesz zobaczyć przykładowy plik tutaj: https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config


0

A dla VB.net znalazłem następujące prace:

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)

0

Nieco bardziej przyszłościowa opcja

W obliczu tego samego pytania ustaliliśmy, że potrzebujemy niestandardowej wersji, StringEnumConverteraby upewnić się, że nasze wartości wyliczeniowe mogą się rozszerzać w czasie, nie niszcząc katastrofalnie po deserializującej stronie (patrz tło poniżej). UżywającSafeEnumConverter poniższego pozwala na zakończenie deserializacji, nawet jeśli ładunek zawiera wartość wyliczenia, która nie ma nazwanej definicji, bliżej do tego, jak działałaby konwersja zamiany na wyliczanie.

Stosowanie:

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

lub

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

Źródło:

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;
    }
}

tło

Kiedy spojrzeliśmy na użycie StringEnumConverter, mieliśmy problem, że potrzebowaliśmy również pasywności w przypadkach, gdy dodano nową wartość wyliczenia, ale nie każdy klient od razu wiedział o nowej wartości. W takich przypadkach StringEnumConverterpakiet z Newtonoft JSON generuje JsonSerializationExceptionbłąd podobny do „Błąd konwersji wartości SomeString na typ EnumType”, a następnie cały proces deserializacji kończy się niepowodzeniem. Było to dla nas przełomowe, ponieważ nawet jeśli klient planował zignorować / odrzucić wartość nieruchomości, której nie rozumiał, nadal musiał być zdolny do deserializacji reszty ładunku!


-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();

-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]  
);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.