JavaScriptSerializer - 将枚举序列化为字符串

JavaScriptSerializer - JSON serialization of enum as string

提问人:Omer Bokhari 提问时间:3/14/2010 最后编辑:John SmithOmer Bokhari 更新时间:5/10/2023 访问量:723896

问:

我有一个包含属性的类,并且在使用 序列化对象时,我的 json 结果包含枚举的整数值而不是它的“名称”。有没有办法在我的 json 中获取枚举作为 a,而无需创建自定义?也许我可以用一个属性来装饰定义或对象属性?enumJavaScriptSerializerstringstringJavaScriptConverterenum

举个例子:

enum Gender { Male, Female }

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

所需的 JSON 结果:

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

理想情况下,使用内置的 .NET 框架类寻找答案,如果不可能,欢迎替代方案(如 Json.net)。

C# asp.net JSON 枚举 javascriptserializer

评论

10赞 Stephen Kennedy 6/6/2015
改成哪个?最高点赞的答案实际上并没有回答问题 - 是的,它在其他上下文中很有用,因此投票,但如果你坚持使用 MS JavaScriptSerializer,它没有任何实际用处,因为本质上你使用页面方法,最重要的是,按照问题的要求。公认的答案说这是不可能的。我的回答虽然有点黑客可以完成工作。

答:

460赞 Matt Dearing 3/14/2010 #1

不,没有可以使用的特殊属性。 序列化为它们的数值,而不是它们的字符串表示形式。您需要使用自定义序列化将 序列化为其名称而不是数值。JavaScriptSerializerenumsenum


如果您可以使用 JSON.Net 而不是 而不是查看 Omer Bokhari 提供的此问题的答案: JSON.net 涵盖了此用例(通过属性)以及内置 .net 序列化程序未处理的许多其他用例。下面是一个链接,比较了序列化程序的特性和功能JavaScriptSerializer[JsonConverter(typeof(StringEnumConverter))]

评论

8赞 BeemerGuy 5/12/2016
@Fabzter -- 您的解决方案使用 Newtonsoft 的 Json 与我合作
1赞 BrainSlugs83 9/21/2016
@BornToCode Json.NET 是 ASP.NET 默认使用的序列化程序。
13赞 BornToCode 9/21/2016
@BrainSlugs83 - 问题是关于使用 JavaScriptSerializer,而不是 Json.NET(如果你查看修订历史,你会看到有一个编辑来澄清这一点),如果你使用 JavaScriptSerializer,该属性将不起作用。JsonConverter
1赞 ryanwebjackson 6/9/2020
“Json.NET 是 ASP.NET 默认使用的序列化程序”——当提出或回答问题时,情况并非如此。(但最重要的是答案的清晰度)
0赞 Noman_1 6/3/2021
[JsonConverter(typeof(StringEnumConverter))] 用于 newtonsoft
2403赞 Omer Bokhari 5/20/2010 #2

我发现 Json.NET 提供了一个属性,并传入了内置类型,从而提供了我正在寻找的确切功能:JsonConverterStringEnumConverter

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

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

有关更多详细信息,请参阅 StringEnumConverter 文档

在其他地方可以更全局地配置此转换器:

  • 枚举本身,如果您希望枚举始终序列化/反序列化为字符串:

      [JsonConverter(typeof(StringEnumConverter))]  
      enum Gender { Male, Female }
    
  • 如果有人想避免属性修饰,可以将转换器添加到 JsonSerializer 中(由 Bjørn Egil 建议):

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

它将适用于它在序列化期间看到的每个枚举(由 Travis 建议)。

  • 或者 JsonConverter(由 banana 推荐):

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

此外,还可以使用 StringEnumConverter(NamingStrategy, Boolean) 构造函数控制大小写以及是否仍接受数字。

评论

9赞 RredCat 11/29/2010
点击链接了解如何在 MVC 应用程序 james.newtonking.com/archive/2008/10/16/ asp.net 中使用它......
2赞 CAD bloke 11/1/2011
以下是该函数的链接:james.newtonking.com/projects/json/help/html/...
67赞 Iggy 8/10/2013
HttpConfiguration 配置 = GlobalConfiguration.Configuration;配置。Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;配置。Formatters.JsonFormatter.SerializerSettings.Converters.Add (new Newtonsoft.Json.Converters.StringEnumConverter());
1赞 Odys 2/19/2014
需要注意的是,默认情况下 ASP.NET MVC 不使用 Json.Net 作为 json 序列化程序,并且需要扩展或手动覆盖每个序列化。Controller
3赞 Seafish 10/8/2017
您可以自定义转换器(例如,用于输出):camelCasenew StringEnumConverter { CamelCaseText = true }
3赞 Sebastian Markbåge 12/28/2011 #3

实际上,您可以使用 JavaScriptConverter 通过内置的 JavaScriptSerializer 来实现此目的。通过将枚举转换为 Uri,可以将其编码为字符串。

我已经描述了如何为日期执行此操作,但它也可用于枚举。.NET JavaScriptSerializer 的自定义 DateTime JSON 格式

33赞 Stephen Kennedy 3/16/2012 #4

这可以通过向属性添加 ScriptIgnore 特性(使其不序列化)并添加一个序列化的属性来轻松完成:GenderGenderString

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

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

评论

32赞 RredCat 4/17/2013
让我试着解释一下。根据设计方案,此解决方案是不正确的。您根据视图目的修改了模型。但是模型必须只包含数据,而不关心表示。您必须将此功能移动到另一层。
5赞 Dima 7/16/2013
实际上,模型是用来从控制器传递数据的,它是控制器,它不关心呈现。引入自动化属性(此处为 GenderString)不会破坏控制器,控制器仍使用 Gender 属性,但提供了对视图的轻松访问。合乎逻辑的解决方案。
19赞 Mariano Desanze 8/24/2013
@RredCat 在“视图模型”中具有特定于视图的属性并没有错。恕我直言,错误是不要将视图模型与域模型分开:blogs.msdn.com/b/simonince/archive/2010/01/26/......
6赞 MEMark 11/4/2013
@RredCat,即使根据某种模式是不正确的,OP对此也没有任何说明,所以这确实是一个正确的答案。(即使我在哲学上可能同意你的观点。
11赞 Mike Mooney 7/22/2015
这个评论线程中迂腐荒谬的自行车脱落令人着迷。
5赞 Ales Potocnik Hahonina 3/27/2012 #5

这是一个老问题,但我想我会做出贡献以防万一。在我的项目中,我对任何 Json 请求都使用单独的模型。模型通常与带有“Json”前缀的域对象同名。模型使用 AutoMapper 进行映射。通过让 json 模型声明一个字符串属性,该属性是域类上的枚举,AutoMapper 将解析为其字符串表示形式。

如果您想知道,我需要为 Json 序列化类提供单独的模型,因为内置序列化器会以其他方式提供循环引用。

希望这对某人有所帮助。

评论

0赞 ledragon 3/28/2013
很高兴学习 Automapper 的那个功能;-)[ScriptIgnore] 属性将删除循环引用
1赞 Ales Potocnik Hahonina 4/5/2013
哦。不知道属性。谢谢!你会在你的 Pocos 上使用它吗?我求助于对任何 Poco 属性使用 MetadataType 定义,只是为了保持它们干净。该属性是否仍可通过元数据工作?
29赞 mheyman 4/26/2012 #6

这个版本的 Stephen 的答案不会更改 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赞 KCD 10/31/2012
我相信这对不适用DataContractJsonSerializerJavaScriptSerializer
1赞 The Senator 8/8/2013
简单,使用本机 .NET 框架序列化程序为我解决了这个问题。
1赞 Daniel Gruszczyk 10/17/2013
对我来说最好的解决方案,因为我不允许使用第三方库(ISO 合规性问题)
0赞 Stephen Kennedy 10/25/2014
当然,这不适用于问题中的序列化器类型。JavaScriptSerializer 序列化未忽略的所有内容,而 DataContractJsonSerializer 需要 DataMember 属性。谢谢你的大喊大叫,但请注意你把我的名字拼错了:)
16赞 biofractal 4/10/2013 #7

下面是一个简单的解决方案,它将服务器端 C# 枚举序列化为 JSON,并使用结果填充客户端元素。这适用于简单枚举和 bitflag 枚举。<select>

我包含了端到端解决方案,因为我认为大多数想要将 C# 枚举序列化为 JSON 的人也可能会使用它来填充下拉列表。<select>

这里是:

示例枚举

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

使用按位 OR 生成权限系统的复杂枚举。因此,您不能依赖简单索引 [0,1,2..] 作为枚举的整数值。

服务器端 - 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);
};

上面的代码使用 NancyFX 框架来处理 Get 请求。它使用 Nancy 的帮助程序方法 - 但不用担心,您可以使用任何标准的 JSON 格式化程序,因为枚举已经投影到一个简单的匿名类型中,可以进行序列化。Response.AsJson()

生成的 JSON

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

客户端 - 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 之前

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

HTML 之后

<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>
182赞 Iggy 8/10/2013 #8

将以下内容添加到 global.asax,以便将 c# 枚举的 JSON 序列化为字符串

  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赞 sq33G 12/24/2013
出于某种原因,我无法让它工作。Fiddler 显示一个顽固的 2 而不是“警告”,即使有这个。另外 - 任何原因要更改为?FormattingIndented
5赞 Greg Z. 3/22/2014
此示例中的第三行已添加到 App_start/webapiconfig.cs 文件中,并在 ASP.NET Web API 2.1 项目中为我做了一个技巧,以返回 REST (json fomat) 调用中枚举值的字符串。
1赞 Anestis Kivranoglou 4/1/2016
有没有办法仅按请求范围设置此属性?
0赞 BrainSlugs83 9/21/2016
@AnestisKivranoglou只需使用具有自己设置的每个请求的自定义 json 序列化程序即可。
3赞 user3791372 12/10/2016
Indented 的第一个序列化程序设置与 OP 问题无关。
46赞 Scott Stafford 12/19/2013 #9

我无法像(@ob)的顶级答案那样更改源模型,而且我不想像@Iggy一样全局注册它。因此,我将 https://stackoverflow.com/a/2870420/237091 和 @Iggy 的 https://stackoverflow.com/a/18152942/237091 结合起来,以允许在 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()
        }
    })

评论

1赞 Bogdan 9/15/2014
如果你有像这样的属性 List<someEnumType,这也很好>
0赞 John Washam 2/16/2021
@Bogdan如前所述,这是我使用每个 Enum 值的字符串值而不是数字值序列化属性的修复方法。List<AnEnumType>
191赞 Juri 11/24/2014 #10

@Iggy答案将 c# 枚举的 JSON 序列化设置为仅用于 ASP.NET(Web API 等)的字符串。

但是,若要使其也适用于临时序列化,请将以下内容添加到起始类(如 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;
});

更多信息请见 Json.NET 页面

此外,要让您的枚举成员序列化/反序列化为特定文本/从特定文本序列化/反序列化,请使用

System.Runtime.Serialization.EnumMember

属性,如下所示:

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

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

评论

14赞 Poulad 9/16/2017
谢谢!我只是在寻找.[EnumMember]
1赞 fiat 8/14/2019
该属性现在被标记为已过时。实例化转换器的新方法:CamelCaseTextnew StringEnumConverter(new CamelCaseNamingStrategy())
0赞 developer learn999 11/11/2020
您放置在 ConfigureServices 或 NET CORE 2 中的 Configure 中的 JsonConvert?
27赞 GuCa 4/21/2015 #11

这是newtonsoft.json的答案

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

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

评论

1赞 Peet 3/14/2018
谢谢你的回答,对我帮助很大!如果你想在PascalCase中定义你的枚举,但你希望在camelCase中序列化它,那么你需要添加到你的JsonConverter类型中,如下所示:true[JsonConverter(typeof(StringEnumConverter), true)]
13赞 Yang Zhang 6/17/2015 #12

可以通过调用 JsonConverter.SerializeObject 创建 JsonSerializerSettings,如下所示:

var result = JsonConvert.SerializeObject
            (
                dataObject,
                new JsonSerializerSettings
                {
                    Converters = new [] {new StringEnumConverter()}
                }
            );
13赞 Greg R Taylor 3/5/2016 #13

请注意,当存在 Description 属性时,序列化没有答案。

这是我支持 Description 属性的实现。

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

枚举:

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

    // Will be serialized as "Applicable"
    Applicable
}

用法:

[JsonConverter(typeof(CustomStringEnumConverter))]
public FooEnum test { get; set; }
20赞 GorvGoyl 4/5/2016 #14

如果您不想使用属性,也可以向 T 添加转换器:JsonSerializerJsonConverter

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

它将适用于该序列化期间看到的每个人。enum

-5赞 Slava 4/19/2016 #15
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]  
);
8赞 hngr18 6/27/2016 #16

以防万一有人发现上述内容不足,我最终解决了这个超载问题:

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

评论

0赞 Dirk Brockhaus 6/14/2019
对于我的当前用例来说,这是一个很好的解决方案:我不想更改序列化程序默认值,并且在使用特性时遇到问题,因为我的属性类型为 IList<EnumType>。
0赞 Jon Grant 7/12/2016 #17

我已使用该库将此解决方案的所有部分放在一起。它修复了枚举问题,还使错误处理变得更好,并且它适用于 IIS 托管服务。它有相当多的代码,所以你可以在 GitHub 上找到它:https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.csNewtonsoft.Json

您必须添加一些条目才能使其工作,您可以在此处查看示例文件: https://github.com/jongrant/wcfjsonserializer/blob/master/Web.configWeb.config

10赞 PeteGO 5/1/2017 #18

对于 .Net Core :-

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

评论

2赞 infl3x 10/27/2017
如果这是 NuGet 包中的那个,它似乎只是 上的扩展方法,而不是 。所以它的用法是.Microsoft.AspNetCore.Mvc.Formatters.JsonIMvcCoreBuilderIMvcBuilderservices.AddMvcCore().AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
42赞 Ashkan S 8/16/2017 #19

Omer Bokhari 和 uri 的答案的组合完全是我的解决方案,因为我想提供的值通常与我在枚举中的值不同,特别是我希望能够在需要时更改我的枚举。

因此,如果有人感兴趣,它是这样的:

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

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

评论

2赞 Prolog 11/18/2018
我使用的是枚举成员,它适用于简单的反序列化任务。可悲的是,在使用 s 进行手动调整时,它被忽略了。Happilly 就像一个魅力。谢谢!JsonPropertyAttributeJTokenEnumMemberAttribute
33赞 st1 6/19/2018 #20

ASP.NET 核心方式:

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

16赞 Yahya Hussein 10/17/2018 #21

对于 ASP.Net 核心,只需将以下内容添加到您的启动类中:

JsonConvert.DefaultSettings = (() =>
        {
            var settings = new JsonSerializerSettings();
            settings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
            return settings;
        });
1赞 kenny 12/19/2018 #22

不确定这是否仍然相关,但我不得不直接写入 json 文件,我想出了以下将几个 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);
        }
    }
}

它确保我所有的 json 键都是小写的,根据 json“规则”开始。将其格式化为干净的缩进,并忽略输出中的 null。Aslo 通过添加 StringEnumConverter,它打印带有字符串值的枚举。

就我个人而言,我认为这是我能想到的最干净的,而不必用注释弄脏模型。

用法:

    internal void SaveJson(string fileName)
    {
        // serialize JSON directly to a file
        using (StreamWriter file = File.CreateText(@fileName))
        {
            LowercaseJsonSerializer.Serialize(file, jsonobject);
        }
    }
1赞 Benjamin Swedlove 5/16/2019 #23

VB.net 我发现了以下作品:

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)
2赞 Dusty 8/7/2019 #24

一个更面向未来的选择

面对同样的问题,我们确定我们需要一个自定义版本,以确保我们的枚举值可以随着时间的推移而扩展,而不会在反序列化方面发生灾难性中断(见下面的背景)。使用以下命令可以完成反序列化,即使有效负载包含没有命名定义的枚举的值,也更接近于整数到枚举转换的工作方式。StringEnumConverterSafeEnumConverter

用法:

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

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

源:

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

背景

当我们考虑使用 时,我们遇到的问题是,当添加新枚举值时,我们还需要被动性,但并非每个客户端都能立即意识到新值。在这些情况下,使用 Newtonsoft JSON 打包会抛出类似于“将值 SomeString 转换为类型 EnumType 时出错”,然后整个反序列化过程失败。这对我们来说是一个交易破坏者,因为即使客户端计划忽略/丢弃它不理解的属性值,它仍然需要能够反序列化其余的有效负载!StringEnumConverterStringEnumConverterJsonSerializationException

评论

0赞 laventnc 8/17/2020
对 .NET 来说仍然相对较新,但出于性能原因,我被告知要避免使用 try catch 表达式。如果是这样的话,序列化程序不是使用序列化程序的坏地方吗?
1赞 Dusty 8/17/2020
@laventnc 尝试...catch 本身不会影响性能,但如果引发异常,则会产生性能开销。这种实现的重点是容错......不允许单个未知枚举值,以防止整个 JSON 有效负载反序列化。比较基础:异常仍会引发,但它将导致整个反序列化过程失败(并且它可能在堆栈中更远的某个地方捕获)。您是否需要这种容错能力是您的用例的产物。StringEnumConveter
67赞 Björn 10/4/2019 #25

在 .net core 3 中,现在可以通过 System.Text.Json 中的内置类实现这一点(编辑:根据文档,System.Text.Json 也可作为 .net core 2.0 和 .net framework 4.7.2 及更高版本的 NuGet 包使用):

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

要为特定属性配置属性修饰,请执行以下操作:JsonStringEnumConverter

using System.Text.Json.Serialization;

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

如果要始终将枚举转换为字符串,请将属性放在枚举本身。

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

评论

3赞 jolySoft 6/9/2021
很好,很干净。
25赞 Serj-Tm 11/11/2019 #26

使用 System.Text.Json Asp.Net Core 3

public void ConfigureServices(IServiceCollection services)
{

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

    //...
 }
-4赞 zilong 12/26/2019 #27
        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();
10赞 Андрей Петрашевич 8/25/2021 #28

使用这个:

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

[Serializable]
[JsonConverter(typeof(StringEnumConverter))]
public enum Gender { Male, Female }
21赞 O. Shai 2/15/2022 #29

对于 .NET 6.0,如果要使用内置 (System.Text.Json)JsonSerializer

然后,它是开箱即用的,你只需要使用内置属性。例如:JsonStringEnumConverter

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

就是这样,但请确保你的包含值与确切的字符串值,否则它将引发异常。外壳似乎不敏感。SomeEnumType

参考: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-customize-properties?pivots=dotnet-6-0#enums-as-strings

评论

0赞 Konrad Viltersten 7/6/2022
我们在 Program 类中将其连接到所有转换中,如下所示:.你觉得怎么样?services.AddControllers().AddJsonOptions(a => a.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()))
0赞 Douglas Gaskell 9/25/2022
我们怎么能有这种行为,而不必用这个属性来装饰每个属性?
0赞 qqtf 4/4/2023
也适用于完整框架 4.8
1赞 Bluefire 5/4/2023
谢谢,Newtonsoft 解决方案在我的情况下不起作用。“使用 System.Text.Json.Serialization;” 它奏效了!
-1赞 Michael K 5/10/2022 #30

对于在 22 年 5 月需要 .NET 6 解决方案并且仍在使用 Newtonsoft 的任何人,您可以像这样全局注册转换器:

var builder = WebApplication.CreateBuilder(args);
...
builder.Services.AddControllers(options => options.RespectBrowserAcceptHeader = true)
.AddNewtonsoftJson(opt =>
{
    opt.SerializerSettings.ContractResolver = new DefaultContractResolver();
    opt.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
})
.AddXmlSerializerFormatters()
.AddXmlDataContractSerializerFormatters();
3赞 neoLord 2/6/2023 #31

命名空间 System.Text.Json.Serialization 具有 JsonStringEnumConverter,可以按如下方式使用。 [JsonConverter(typeof(JsonStringEnumConverter))]