5

私はここでゲームに取り組んでおり、このかなり興味深いバグを見つけました。次の列挙型があるとします。

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

基本クラス

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

    public ItemType Type = ItemType.Misc;
}

およびその 2 つのインスタンス:

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

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

これが私に起こったことです: コンストラクターでタイプを Food にしたいことを指定したにもかかわらず、最初のインスタンスのタイプは基本クラスで事前に初期化されたままになります。2 番目のインスタンスのタイプは、Tools に正しく設定されます。

IF、次のような新しい列挙値 BEFORE Food を追加しました。

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

次に、最初のインスタンスのタイプは、予想どおり Food になります。2 番目のインスタンスのタイプも正しいでしょう。

この動作の原因は何ですか? 簡単に説明すると、コンストラクターで Type が列挙型の最初の値に設定されたすべてのインスタンスは、実際には BaseItem 定義にあった値に戻ります。最初の列挙値の前に余分な値を追加すると、明らかに問題が解決しました。しかし、それは間違っているので、何が問題を引き起こしたのか知りたいです。

ありがとう!

--- 後で編集 --- これが役立つ場合: BaseItem 内の「Type」フィールドに初期化を行わず、中括弧コンストラクターのみを残して初期化を行うと、列挙型に「Nothing」値を追加しなくてもすべて正常に機能します。 .

これにつきましては申し訳ございません; さらに掘り下げた後、それは Unity のみのバグのようです。他の何人かの人々もそれに遭遇しました。問題は解決しました。誰もが私から投票を受け取り、私自身の回答を追加します。他の Unity ユーザーが見つけてくれるかもしれません。ご協力とご関心をお寄せいただきありがとうございます。

4

5 に答える 5

2

ここで情報を検索する他のUnityユーザーがいる場合は、それが.NETの動作の問題であると考えて、Unityのみのバグのようです。他の人もそれに遭遇しました。この種のものについては、クラス自体での初期化を避けるか、プロパティを使用してください。

これは間違いなくMicrosoft.NETの問題ではなく、Mono .NETの問題でもありません(同じコードでいつでもMonoプロジェクトを開始でき、正しく機能します)。

于 2012-11-27T23:11:14.287 に答える
1

列挙型を宣言するコードが、クラスを宣言するコードまたは変数と変数を導入するItemTypeコード以外の別のアセンブリ(プロジェクト)にある場合は、列挙型の定義を変更するときにすべてのアセンブリを再コンパイルすることが重要です。。BaseItemIns1Ins2ItemType

于 2012-11-27T22:15:30.417 に答える
0

これは単なる推測ですが、列挙型の最初の値は0と同等であるため、定義(ItemType.Misc、または5)でデフォルト値を設定することと、値をに戻す型初期化子を使用することの組み合わせである可能性があります。デフォルト値(ItemType.Food、または0)がない場合は、指定したデフォルト値(ItemType.Misc)が保持されます。

ちなみに、これは重要ですが、実際にはコンストラクターを定義していません。構文

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

...はコンストラクターの呼び出しではなく、型初期化子の呼び出しです。はい、デフォルトのコンストラクターが呼び出されますが、そのコンストラクターでは何も起こりません。

実際にコンストラクターを使用して、そこでItemTypeのデフォルト値を設定すると、この問題は解消されると思います。何かのようなもの:

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

この点を明確に述べているものを読んだことは覚えていませんが、使用した構文を使用してパブリックプロパティまたはフィールドのデフォルト値を設定するべきではないと思います。設定する必要がある場合は、簡単に上書きできるようにコンストラクターで設定してください。使用した構文は、クラスの外部から設定できるものよりも、プライベートバッキングフィールドに適しています。

于 2012-11-27T22:16:05.117 に答える
0

アイデアを持ってください。それが機能するかどうかはわかりません。初期化後に BaseItem のコンストラクターが呼び出されているようです。ブレークポイントを設定して、BaseItem のコンストラクターがいつ呼び出されるかを確認してください。または、Name と Type を設定する前に、BaseItem のコンストラクターを明示的に呼び出すこともできます。

于 2012-11-27T22:08:10.287 に答える
0

このコードは正常に動作するはずです。おそらく、あなたの問題を再現する最小限のプログラムを投稿してみてください。

あなたが知っておくべきことが1つあります。使用しているのはコンストラクターではなく、オブジェクトの初期化です。主な違いは、オブジェクト初期化子を使用すると、結果のコードが最初にオブジェクトの既定のコンストラクターを呼び出し、次にプロパティ/フィールドを設定することです。

したがって、このコード:

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

このより明示的なアプローチを使用すると、間接的にバグが解決される可能性があり、少なくともコードのエラーが発生しにくくなると思います。

于 2012-11-28T00:20:55.053 に答える