json 使用Unity在C#中反序列化位标志枚举

xuo3flqw  于 2023-08-08  发布在  C#
关注(0)|答案(1)|浏览(139)

我有个团结计划。使用我可以使用的常用JSON工具,我尝试反序列化一个使用位标志(即类似于)的枚举

[Flags]
enum Terrain 
{
  NORMAL = 0,
  FOREST = 1,
  SWAMP = 2,
  CAVE = 4 
}

字符串
在json中,它类似于CityTerrain:“FOREST”,但是似乎反序列化不喜欢人类可读的字符串枚举(我假设它想要一个整数),这对我来说特别麻烦,当我想要能够合并标志时,位标志。森林|洞穴
XML处理的位标志枚举开箱即用。为什么json这种上级的格式看起来与它斗争得如此之厉害?我应该做一个枚举 Package 器来处理这个的反序列化吗?不管我做什么,我觉得我的解决方案将是笨重的,我会不喜欢它。
最终它需要是人类可读的,我不会接受一个“解决方案”,我的bitflag枚举必须在json中表示为5。这个练习的全部要点是它需要是人类可读的,但仍然是可反序列化的。

rks48beu

rks48beu1#

对于Newtonsoft.Json

可以使用StringEnumConverter并将其沿着到

var converter = new StringEnumConverter();
    
var json = JsonConvert.SerializeObject(example, Formatting.Indented, converter);

字符串
和(显然是可选的)

var example = JsonConvert.DeserializeObject<Example>(json, converter);


在我的反序列化测试中,它似乎也只适用于

var example = JsonConvert.DeserializeObject<Example>(json);

对于System.Text.Json

你可以使用等价的JsonStringEnumConverter并通过例如这样的选项传递它。

// IncludeFields depends on whether your type uses fields or properties
// by default System.Text.Json only considers properties
// so to reflect the behavior of Newtonsoft I enabled also fields
var options = new JsonSerializerOptions() { WriteIndented = true,  IncludeFields = true };
options.Converters.Add(new JsonStringEnumConverter());
    
var json = JsonSerializer.Serialize(example, options);


和/或

var example = JsonSerializer.Deserialize<Example>(json, options);


.Net Fiddle for both above

(以下JsonUtility也适用):两者基本上都经过ToStringEnum.Parse,所以在json中它将读取例如。

"FOREST, SWAMP"


如果出于某种原因,您确实需要使用FOREST|SWAMP,则必须实现自己定制JsonConverter (Newtonsoft)或相应的JsonConverter (System.Text.Json)
基本上使用相同的和做一些类似的(伪代码)

// When serializing Terrain -> string
var enumString = value.ToString().Replace(", ", "|");


和/或

// When deserializing string -> Terrain
var enumValue = (Terrain)Enum.Parse(enumString.Replace("|", ", "));

内置JsonUtility

不幸的是,没有类似的东西。相反,您必须覆盖整个类的序列化,例如。

public class Example : ISerializationCallbackReceiver
{
    public string Name;
    
    [NonSerialized]
    public Terrain Terrain;
    
    public int SomeVlaue;

    [SerializeField]
    private string terrain;
    
    
    public void OnBeforeSerialize()
    {
        terrain = Terrain.ToString();
    }

    public void OnAfterDeserialize()
    {
        Terrain = (Terrain)Enum.Parse(typeof(Terrain), terrain);
    }
}

备注

  • 但要记住,这也会影响它在Inspector =>中的显示方式。然后,您可能希望实现一个自定义Inspector,以基本上“恢复”显示,并再次将其绘制为枚举标志字段。
  • 您还必须对每个包含Terrain的类型重复此操作,并且应进行JSON序列化

相关问题