1305

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

举个例子:

enum Gender { Male, Female }

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

所需的 JSON 结果:

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

理想情况下寻找内置 .NET 框架类的答案,如果不可能的话(如 Json.net)是受欢迎的。

4

29 回答 29

2265

我发现Json.NETStringEnumConverter通过一个属性提供了我正在寻找的确切功能:

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

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

StringEnumConverter有关文档的更多详细信息。

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

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

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

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

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

  • 或 JsonConverter (香蕉建议):

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

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

于 2010-05-20T00:58:33.230 回答
450

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


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

于 2010-03-14T06:21:10.860 回答
180

将以下内容添加到 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());
于 2013-08-09T18:06:33.353 回答
170

@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
}
于 2014-11-24T11:24:47.173 回答
44

我无法像(@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()
        }
    })
于 2013-12-18T16:39:45.317 回答
39

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; }
}
于 2017-08-16T10:52:58.757 回答
37

在 .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 }
于 2019-10-04T10:51:27.387 回答
33

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

于 2018-06-19T08:08:26.123 回答
31

这很容易通过向属性添加一个ScriptIgnore属性Gender,使其不被序列化,并添加一个被序列化的属性GenderString来完成:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

    string GenderString { get { return Gender.ToString(); } }
}
于 2012-03-15T17:38:34.723 回答
27

这个版本的斯蒂芬的答案不会改变 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; 
        }
    }
}
于 2012-04-26T13:55:37.653 回答
25

这是 newtonsoft.json 的答案

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}
于 2015-04-21T09:47:56.430 回答
22

带有 System.Text.Json 的 Asp.Net Core 3

public void ConfigureServices(IServiceCollection services)
{

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

    //...
 }
于 2019-11-11T00:31:52.673 回答
19

JsonSerializer如果您不想使用JsonConverter属性,也可以添加转换器:

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

它适用于enum它在序列化过程中看到的每一个。

于 2016-04-05T11:15:39.807 回答
16

这是一个简单的解决方案,它将服务器端 C# 枚举序列化为 JSON,并使用结果填充客户端<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 的Response.AsJson()辅助方法 - 但不用担心,您可以使用任何标准的 JSON 格式化程序,因为枚举已经被投影为一个简单的匿名类型,准备好进行序列化。

生成的 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>
于 2013-04-10T10:06:43.220 回答
16

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

JsonConvert.DefaultSettings = (() =>
        {
            var settings = new JsonSerializerSettings();
            settings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
            return settings;
        });
于 2018-10-17T05:49:14.043 回答
13

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

var result = JsonConvert.SerializeObject
            (
                dataObject,
                new JsonSerializerSettings
                {
                    Converters = new [] {new StringEnumConverter()}
                }
            );
于 2015-06-17T12:29:49.097 回答
12

注意到当有描述属性时,序列化没有答案。

这是我支持 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; }
于 2016-03-05T08:29:03.173 回答
10

对于 .Net 核心:-

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
    ...
}
于 2017-04-30T22:47:24.357 回答
8

以防万一有人发现上述不足,我最终解决了这个重载:

JsonConvert.SerializeObject(objToSerialize, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())
于 2016-06-27T08:35:49.150 回答
7

用这个:

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

[Serializable]
[JsonConverter(typeof(StringEnumConverter))]
public enum Gender { Male, Female }
于 2021-08-25T14:10:14.080 回答
5

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

如果您想知道,我需要 Json 序列化类的单独模型,因为否则内置序列化程序会提供循环引用。

希望这可以帮助某人。

于 2012-03-27T15:58:04.007 回答
3

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

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

于 2011-12-28T10:29:30.070 回答
2

一个更面向未来的选择

面对同样的问题,我们确定我们需要一个自定义版本StringEnumConverter来确保我们的枚举值可以随着时间的推移而扩展,而不会在反序列化方面造成灾难性的破坏(参见下面的背景)。SafeEnumConverter即使有效负载包含没有命名定义的枚举值,使用以下内容也可以完成反序列化,更接近于 int-to-enum 转换的工作方式。

用法:

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

背景

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

于 2019-08-06T18:46:49.560 回答
2

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

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

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

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

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

于 2022-02-15T12:43:05.140 回答
1

不确定这是否仍然相关,但我不得不直接写入一个 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“规则”开始的小写字母。将其格式化为干净的缩进并忽略输出中的空值。Aslo 通过添加 StringEnumConverter 它打印带有字符串值的枚举。

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

用法:

    internal void SaveJson(string fileName)
    {
        // serialize JSON directly to a file
        using (StreamWriter file = File.CreateText(@fileName))
        {
            LowercaseJsonSerializer.Serialize(file, jsonobject);
        }
    }
于 2018-12-19T08:28:54.703 回答
1

对于 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)
于 2019-05-15T21:44:36.660 回答
0

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

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

于 2016-07-12T10:45:29.587 回答
-4
        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();
于 2019-12-26T03:17:53.200 回答
-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]  
);
于 2016-04-19T14:50:38.960 回答