【问题标题】:Editing array also changes another array [duplicate]编辑数组也会更改另一个数组[重复]
【发布时间】:2021-04-26 16:12:52
【问题描述】:

所以我在 Windows 控制台中制作了一个小游戏(只是为了好玩和测试理论),但我遇到了 DrawGame() 方法的问题。

我正在创建一个新的字符串数组 (string[] _CompleteMap),其值是从 CurrentMap.MapData(也是一个字符串数组)分配的:

string[] _CompleteMap = CurrentMap.MapData;

我使用CurrentMap.MapData 作为空白地图,然后更改字符串中的字符以表示玩家和生物。 但是当我对_CompleteMap 进行更改时,它似乎也在更改CurrentMap.MapData 中的值...

我不知道为什么会这样,它会留下用户走过的痕迹。

任何支持都会有所帮助,如果需要,我可以发布代码。

using System;
using System.Text;
using System.Threading;
using ConsoleAdventure.Engine.BaseClasses;
using Database = ConsoleAdventure.Engine.Database;

namespace ConsoleAdventure
{
    class Program
    {
        private static bool whileGameScene = true;
        private static Engine.BaseClasses.MapBase CurrentMap;

        static unsafe void Main(string[] args)
        {
            // Load and populate the databases.
            Database.ItemDB.LoadItemDB();
            Database.MapDB.LoadMapDB();

            // Set demo map
            CurrentMap = Database.MapDB.Maps[0];

            // Hide cursor
            Console.CursorVisible = false;

            // Start a new thread to capture the user inputs
            new Thread(() =>
                        {
                            while (true)
                            {
                                Thread.CurrentThread.IsBackground = true;

                                ConsoleKeyInfo cki = Console.ReadKey();

                                if (cki.Key == ConsoleKey.A && Player.Data.Location.X > 0)
                                    Player.Data.Location.X--;
                                else if (cki.Key == ConsoleKey.D)
                                    Player.Data.Location.X++;
                                else if (cki.Key == ConsoleKey.W && Player.Data.Location.Y > 0)
                                    Player.Data.Location.Y--;
                                else if (cki.Key == ConsoleKey.S)
                                    Player.Data.Location.Y++;

                                CheckWarpPoints();
                            }        
                        }).Start();

            // Draw the game
            while (whileGameScene)
            {
                DrawGame();
            }
        }

        /// <summary>
        /// Check if player has stood on a warp zone
        /// </summary>
        private static void CheckWarpPoints()
        {
            foreach (MapBase.WarpPoint warp in Database.MapDB.Maps[Player.Data.CurrentMap].WarpPoints)
            {
                if (Player.Data.Location.X == warp.From.X && Player.Data.Location.Y == warp.From.Y)
                {
                    Player.Data.CurrentMap = warp.ToMapIndex;
                    Player.Data.Location = warp.To;
                }
            }
        }

        public static void DrawGame()
        {
            string[] _CompleteMap = CurrentMap.MapData;

            StringBuilder _sbRow = new StringBuilder();

            foreach (var _object in CurrentMap.MapObjects)
            {
                _sbRow = new StringBuilder(_CompleteMap[_object.CurrentLocation.Y]);
                _sbRow[_object.CurrentLocation.X] = _object.Icon;
                _CompleteMap[_object.CurrentLocation.Y] = _sbRow.ToString();
            }

            _sbRow = new StringBuilder(_CompleteMap[Player.Data.Location.Y]);
            _sbRow[Player.Data.Location.X] = 'X';
            _CompleteMap[Player.Data.Location.Y] = _sbRow.ToString();

            for (int i = 0; i < _CompleteMap.Length; i++)
            {
                Console.SetCursorPosition(0, i);
                Console.WriteLine(_CompleteMap[i]);
            }
        }
    }
}

【问题讨论】:

    标签: c# arrays console


    【解决方案1】:

    由于数组是引用类型,当你这样做时:

    string[] _CompleteMap = CurrentMap.MapData;
    

    您实际上是在创建一个新变量,该变量指向与CurrentMap.MapData 相同的内存位置,并且当您通过CurrentMap.MapData 引用该位置时,您通过_CompleteMap 对该位置所做的任何更改也会显示出来。

    相反,您可以根据现有数组的内容创建一个新数组:

    string[] _CompleteMap = CurrentMap.MapData.ToArray();
    

    现在它指向了一个不同的位置,所以修改这个位置的数组不会影响到原来位置的数组。


    但是,需要注意的一点是,如果 MapData 是一个引用类型的数组,并且您使用 ToArray() 复制它,那么即使您现在有一个包含相同数据的新数组,如果您操作数组副本中的其中一个对象,对该对象的更改也会出现在原始数组中。

    这是因为我们做了一个的拷贝。如果我们不想要这种行为,那么我们需要做一个 deep 副本,我们还为数组中的每个对象创建新的(克隆的)实例。有东西要研究!!

    例如:

    class Person
    {
        public string Name { get; set; }
    }
    
    class Program
    {
        static void Main()
        {
            // Original array has a person named John
            Person[] people = new [] { new Person { Name = "John" } };
    
            // Create a shallow copy of the array
            Person[] peopleCopy = people.ToArray();
    
            // Change John's name in the copy
            peopleCopy[0].Name = "James";
    
            // At this point, people[0].Name is also "James", since it's the same person!
    
            // However changes to the array itself are discreet
            peopleCopy[0] = new Person { Name = "Mary" };
    
            // At this point, people[0].Name is still "James", since we did
            // not modify the existing object, but instead created a new one
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-29
      • 2013-12-18
      相关资源
      最近更新 更多