0

最近、XNA で作成された単純なゲームの優れたテンプレートであるGame State Management (詳細: create.msdn.com/en-US/education/catalog/sample/game_state_management ) を使い始めました。

私は数日間その実装を分析してきましたが、このメソッドのLoadingScreen.csに疑いがあります。

/// <summary>
/// The constructor is private: loading screens should
/// be activated via the static Load method instead.
/// </summary>
private LoadingScreen(ScreenManager screenManager, bool loadingIsSlow,
                      GameScreen[] screensToLoad)
{
    this.loadingIsSlow = loadingIsSlow;
    this.screensToLoad = screensToLoad;

    TransitionOnTime = TimeSpan.FromSeconds(0.5);
}

参照の代入がある理由がわかりません: this.screensToLoad = screensToLoad;.Clone()代わりにメソッド のようなものを使用しないのはなぜですか?


[編集]

わかりました... 私の問題は XNA や Game State Management ではないと思います。私が疑問に思っていることを説明するコードを用意しました。

コードは次のとおりです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace test
{
    public class a
    {
        public int number = 3;
    }

    public class b
    {
        public a tmp;

        public void f(a arg)
        {
            tmp = arg; // (*?*) isn't it dangerous assigning?
        } 
    }

    class Program
    {
        static void Main(string[] args)
        {
            b temp_b = new b();

            {// (*!*) CODE BLOCK COMES HERE:
                a temp_a = new a();
                temp_b.f(temp_a);
                temp_a.number = 4;
            }

            // TROUBLE EXPLANATION:
            // We are outside of code block which I marked with (*!*)
            // Now reference 'temp_a' is inaccessible. 
            // That's why line of code which I marked with (*?*) is dangerous.
            // We saved 'temp_a' which is no longer accessible in 'temp_b' object.
            // 
            // Now computer's memory pointed by reference, which is saved in 'temp_b.tmp' (and was saved in 'temp_a'),
            // can be overriden by code which comes somewhere below this comment (or even in another thread or process).
            //
            // I think the same situation is in XNA GSM's piece of code.
            // The only solution in my opinion is deep copy (AFAIK .Clone() can be implemented as shallow or deep copy).

            Console.WriteLine(temp_b.tmp.number); // result is 4
                                                  // because we copied reference
                                                  // For me it's strange that this line was printed. As I mentioned above
                                                  // memory intended for 'temp_a' could be reused and overwritten.
        }
    }
}

便宜上、ここに同じコードを示します: ideone.com/is4S3

上記のコードに質問と疑問を入れました(コメントを参照)。

4

3 に答える 3

1

これは、ライブラリを作成した人の好みに完全に依存するようなものですが、おそらくLoad()メソッドに次のシグネチャがあるためです。

public static void Load(ScreenManager screenManager, bool loadingIsSlow,
                        PlayerIndex? controllingPlayer,
                        params GameScreen[] screensToLoad)

キーワードscreensToLoadを使用して定義されていることに注意してください。paramsつまり、次のように呼び出す必要があります。

LoadingScreen.Load(manager, false, null, s1, s2, s3, s4, s5);

s1 ... sN はロード中の画面です。

この使用例では、呼び出し元のコードは実際には配列への参照を持っていないため、配列のクローンを作成しても、時間とメモリが無意味に浪費されます。あなたの下からその内容が変更される可能性はかなり低いです.

于 2012-05-04T09:42:58.597 に答える
0

screensToLoad の浅いコピーを行う (配列のみをコピーする) ことは理にかなっていますが、この他の回答で指摘されているように、それを行わなくても通常は問題は発生しません。

ディープコピーを作成するのは間違っています。画面はステートフルなオブジェクトであり、複製すると、ユーザーが通常期待する効果が得られません。たとえば、 の呼び出し後に元の画面に登録されたすべてのハンドラは、元の画面ではなくコピーを保持しているためLoad、「デッド」画面に登録されます。ScreenManager

于 2012-05-04T19:27:19.957 に答える
0

画面オブジェクトは、画面マネージャーによって管理されるように作成されます...

元の画面が使い物にならなくなるので、クローンを作成する意味がありません...

たぶん、スクリーンマネージャーがファクトリであり、タイプごとにスクリーンを作成し、IDまたはカスタムパラメーターで初期化されるスクリーンを返す方が良いでしょう...

しかし、このコードは学習するためのサンプルからのものであり、複雑なコードを持つことを期待すべきではないと思います...

于 2012-05-04T19:41:54.600 に答える