C# 扩展时,检查器引用的统一枚举变得无序 问题:

C# 扩展时,检查器引用的统一枚举变得无序 问题:,c#,serialization,enums,unity3d,C#,Serialization,Enums,Unity3d,当枚举在引用的索引之前添加了新条目时,游戏对象脚本通过检查器变量引用的枚举将变得无序 细节: 因此,我有多个系统,如项目列表、本地化字符串等,它们是通过解析外部文件动态构建的。此解析创建枚举,用于通过脚本检查器变量引用gameobject的项目。以下是我的本地化系统解析的输出作为示例: public enum LocaleID { LocalisedStrings_ENGB, LocalisedStrings_ENUS, //.

当枚举在引用的索引之前添加了新条目时,游戏对象脚本通过检查器变量引用的枚举将变得无序

细节: 因此,我有多个系统,如项目列表、本地化字符串等,它们是通过解析外部文件动态构建的。此解析创建枚举,用于通过脚本检查器变量引用gameobject的项目。以下是我的本地化系统解析的输出作为示例:

    public enum LocaleID 
    {
        LocalisedStrings_ENGB,
        LocalisedStrings_ENUS,

        //...

        MAX,
    }

    public enum StringID 
    {
        String_EMPTY,
        String_Inventory,
        String_Recipes,
        String_Tools,
        String_Journal,

        //...
    }

public static class LocalisedStrings
{
    private static string[] SCLocalisedStrings_ENGB = 
    {
        "",
        "Inventory",
        "Recipes",
        "Tools",
        "Journal",

        //...
    }

    private static LocaleID currentLocale = (LocaleID)0;
    private static string[] activeSC = SCLocalisedStrings_ENGB;

    public static void SetLocale(LocaleID newLocale)
    {
        currentLocale = newLocale;
        switch(newLocale)
        {
            case LocaleID.LocalisedStrings_ENGB:
                activeSC = SCLocalisedStrings_ENGB;
            break;
            case LocaleID.LocalisedStrings_ENUS:
                activeSC = SCLocalisedStrings_ENUS;
            break;
        }
    }

    //entry interface: 
    public static string Get(StringID stringID)
    {
        return activeSC[(int)stringID];
    }
}
这只是通过基于设置区域设置的枚举索引返回字符串。 因此,我会在一个角色上曝光一个NPC的名字,比如:

[SerializeField]
public StringID SpeakerTitle;
并通过检查员确认

这是一个非常明显的问题,也是预期的问题-如果对枚举进行不同的分析,例如在顶部添加一个额外的条目(例如用于排序)或删除一个额外的条目(用于清理过时的条目),那么所有被引用的枚举都将出现1点的无序,因为它们将引用枚举条目的索引

一个简单的解决方案是强制执行一条规则,只在末尾添加内容,而从不删除过时的条目。这会变得相当浪费,因此显然不是很可取


对这个问题有什么建议的解决方案?有没有其他人如何处理这种相当普遍的情况的例子?我的首选当然是可以排序并在任何地方添加新条目的内容,但我们不能拥有我们想要的一切:)

只需为条目指定显式数值:

public enum StringID 
{
    String_EMPTY = 0,
    String_Inventory = 1,
    String_Recipes = 2,
    String_Tools = 3,
    String_Journal = 4,

    //...
}
这样,排序与值完全无关。请注意,您可以回顾性地执行此操作,或者在需要进行突破性更改时以“及时”的方式执行此操作


(我个人也会去掉
字符串
前缀,但那是另一回事。)

我会使用显式映射而不是裸数组;例如:

private static Dictionary<StringID,string> SCLocalisedStrings_ENGB = 
    new Dictionary<StringID,string>
{
    {StringID.String_EMPTY, ""},
    {StringID.String_Inventory, "Inventory"},
    //...
};
嗯。。。实际上,我可能会将外部文件中的翻译作为键/值对,但是。。。嗯


注意:您始终可以将字典数据放回有序数组中;但是,使用显式映射可以避免顺序的影响。

Unity内部只存储枚举值,因此,如果您将枚举扩展到末尾以外的任何位置,则您可以移动数字,Unity将根据其存储的值而不是枚举的名称更改所选枚举。谢谢Jon,现在,我对所有原始/内部代码引用的实现都采用了这种方法,并且在解析器中为外部数据实现了一个阶段,用于比较和跟踪预先存在的条目以保留它们的索引。我必须承认,这是我的退路,或“b计划”方法——这是我通常采用的方法,因为我在过去8年中过度接触UE3,所以我会采用堆叠枚举或位字段分类和索引。我希望我错过了一些其他明显的方法或使用模式来更好地管理这种常见情况,但看起来这仍然是最好的方法!我喜欢将内部数据存储在密钥/值对中进行本地化的数据结构,这对于一些系统来说更方便。但是,除非我遗漏了什么,否则这种方法不会解决在被引用的键字段中添加/删除条目的解析情况(例如,在外部,某些内容仍然引用n的StringID,如果它受到碰撞,可能会改变索引位置)?
string val;
return LocaleStrings.TryGetValue(key, out val) ? val : DefaultStrings[key];