C#枚举的奇怪行为

时间:2012-11-27 22:01:51

标签: c# class enums

我正在这里开展游戏,并发现了这个相当有趣的错误。假设你有这个枚举:

public enum ItemType 
{
    Food,
    Weapon,
    Tools,
    Written,
    Misc
};

基类

public class BaseItem
{
    public string Name = "Default Name";

    public ItemType Type = ItemType.Misc;
}

及其两个实例:

Ins1 = new BaseItem
{
   Name = "Something",
   Type = ItemType.Food
};

Ins2 = new BaseItem
{
   Name = "Something too",
   Type = ItemType.Tools
}

这就是我发生的事情:第一个实例的类型将保留为基类中的预初始化,即使我在其构造函数中指定我希望类型为Food。 第二个实例的类型将正确设置为工具。

如果,我在食物之前添加了一个新的枚举值,例如:

public enum ItemType 
{
    Nothing,
    Food,
    Weapon,
    Tools,
    Written,
    Misc
};

然后,正如预期的那样,第一个实例的类型将是Food。第二个实例的类型也是正确的。

可能导致此行为的原因是什么?简而言之,所有其类型已在构造函数中设置为枚举的第一个值的实例实际上将返回到它们在BaseItem定义中具有的值。 在第一个枚举值之前添加额外的值可以解决问题,显然;但这是错的,所以我想知道可能导致这个问题的原因。

谢谢!

---后来编辑--- 如果这有帮助:不对BaseItem中的“Type”字段进行任何初始化,只留下大括号构造函数进行初始化,一切正常,而不向枚举添加“Nothing”值。

对此感到抱歉;经过一些挖掘,似乎它只是一个Unity的bug。其他一些人也遇到过它。我解决了这个问题;每个人都得到我的投票,我会添加自己的答案;也许其他一些Unity用户会找到它。非常感谢您的帮助和兴趣!

5 个答案:

答案 0 :(得分:2)

如果有其他Unity用户在这里搜索信息,认为这是一些.NET行为问题: 它似乎只是一个Unity的错误。其他人也遇到过它。只是避免在类本身中为这种东西进行任何类型的初始化,或者使用属性。

这绝对不是Microsoft .NET问题,也不是Mono .NET问题(您可以随时使用相同的代码启动Mono项目,并且它可以正常工作)。

答案 1 :(得分:1)

如果声明枚举ItemType的代码在另一个程序集(项目)中,而不是声明BaseItem类的代码或引入Ins1和{{1的代码变量,然后在更改Ins2枚举的定义时重新编译所有程序集至关重要。

答案 2 :(得分:0)

只是有个主意。不确定它是否会起作用。初始化后,似乎正在调用BaseItem的构造函数。尝试设置一个断点,看看何时调用BaseItem的构造函数。或者您可以在设置Name和Type之前尝试显式调用BaseItem的构造函数。

答案 3 :(得分:0)

这只是一个猜测,但是,因为Enum的第一个值等于0,可能是在定义(ItemType.Misc或5)中设置默认值的组合加上使用设置的类型初始值设定项如果您没有默认值(ItemType.Food或0)会导致您指定的默认值(ItemType.Misc)被保留,那么它将返回到原来的值。

顺便说一下,这很重要,实际上并没有定义构造函数。语法

Ins1 = new BaseItem
{
   Name = "Something",
   Type = ItemType.Food
};

...不是对构造函数的调用,而是对类型初始值设定项的调用。是的,默认构造函数被调用,但在该构造函数中没有任何反应。

我打赌,如果你真的使用构造函数并在那里设置ItemType的默认值,你会看到这个问题消失了。类似的东西:

public BaseItem()
{
    this.Type = ItemType.Misc;
}

虽然我不记得阅读任何明确说明这一点的内容,但我觉得你不应该使用你使用的语法为公共属性或字段设置默认值。如果需要设置,请在构造函数中设置它,以便可以轻松覆盖它。您使用的语法更适合私有支持字段,而不是可以从类外部设置的内容。

答案 4 :(得分:0)

此代码应该可以正常工作。也许您应该尝试发布一个可以重现问题的最小程序,因为它必须是由其他东西产生的。

你应该注意一件事。你使用的不是构造函数,它是一个对象初始化。主要区别在于,当您使用对象初始值设定项时,生成的代码首先调用对象上的默认构造函数,然后设置属性/字段。

所以这段代码:

var myItem = new BaseItem
{
    Name = "something",
    Type = ItemType.Misc
}

实际上相当于:

var myItem = new BaseItem();
myItem.Name = "something";
myItem.Type = ItemType.Misc;

你可能想要的是定义一个构造函数,如下所示:

class BaseItem
{
    public BaseItem(string name, ItemType type)
    {
        this.Name = name;
        this.Type = type;
    }

    // ...
}

然后像这样使用它:

var myItem = new BaseItem("something", ItemType.Misc);

我猜想使用这种更明确的方法可能会间接解决您的错误,并且至少可能会使您的代码更不容易出错。