C# Singleton stackoverflow
本文关键字:stackoverflow Singleton | 更新日期: 2023-09-27 18:31:46
我正在尝试制作一个使用状态机的游戏。"GameState"通过从"World"类(单例)调用getInstance()来创建世界(在进入时)。
世界单例有一个包含"平铺"对象的 2D 列表(世界由图块组成)。在 World 类的构造函数中,列表由嵌套的 for 循环填充,该循环使用 SimpleTileFactory 类创建磁贴并将它们放入列表中。
问题是我得到了一个StackOverflow。我调试了代码,发现 World 单例的构造函数被调用了不止一次,这可能会导致堆栈溢出。我找不到为什么它被调用不止一次,并且感觉我忽略了一些简单的东西。我的单例正确吗?
守则如下。
提前谢谢。
游戏状态类
public partial class GameState : UserControl, IState<MainView>
{
private bool ready = false;
public GameState()
{
InitializeComponent();
}
public void enter(MainView owner)
{
this.Width = owner.Width;
this.Height = owner.Height;
this.Location = new Point(0, 0);
owner.Controls.Add(this);
World.getInstance();
this.ready = true;
}
public void update(MainView owner)
{
this.Refresh();
}
public void exit(MainView owner)
{
owner.Controls.Remove(this);
}
public bool isReady()
{
return this.ready;
}
private void GameState_Paint(object sender, PaintEventArgs e)
{
//for (int i = 0; i < World.getInstance().tiles.Count; i++)
//{
// for (int j = 0; j < World.getInstance().tiles[0].Count; j++)
// {
// //e.Graphics.DrawImage(new Image(), new Rectangle());
// }
//}
}
}
世界级
class World
{
private static World instance;
public GameResources gameResources;
public SimpleTileFactory tileFactory;
public List<List<Tile>> tiles = new List<List<Tile>>();
public Size worldSize = new Size(100, 100);
private World()
{
this.gameResources = new GameResources();
this.tileFactory = new SimpleTileFactory();
for (int i = 0; i < worldSize.Height; i++)
{
List<Tile> row = new List<Tile>();
for (int j = 0; j < worldSize.Width; j++)
{
row.Add(tileFactory.createTile(new Point(j, i)));
}
}
}
public static World getInstance()
{
if (instance == null)
{
instance = new World();
}
return instance;
}
}
简单瓷砖工厂类
class SimpleTileFactory
{
public SimpleResourceFactory resourceFactory = new SimpleResourceFactory();
private Random random = new Random();
private int maxNumOfResourcesPerTile = 5;
public SimpleTileFactory()
{
}
public Tile createTile(Point location)
{
//create tile
Tile tile = new Tile();
tile.location = location;
//give tile terrain type
Terrain terrain = new Terrain();
terrain.type = random.Next(0, World.getInstance().gameResources.terrainNames.Count);
terrain.name = World.getInstance().gameResources.terrainNames[terrain.type];
terrain.accessability = 1000;
//add resources to terrain
int numberOfResources = random.Next(0, maxNumOfResourcesPerTile + 1);
for (int i = 0; i < numberOfResources; i++)
{
terrain.resources.Add(resourceFactory.createTerrainResource(terrain.type));
}
tile.terrain = terrain;
return tile;
}
}
简单资源工厂类
class SimpleResourceFactory
{
public List<string> resourceNames = new List<string>();
public List<Image> resourceImages = new List<Image>();
private Random random = new Random();
public SimpleResourceFactory()
{
resourceNames.Add("asdfasfd");
resourceNames.Add("asdfasfd");
resourceNames.Add("asdfasfd");
}
public TerrainResource createTerrainResource(int terrainType)
{
TerrainResource resource = new TerrainResource();
resource.type = random.Next(0, resourceNames.Count);
resource.name = this.resourceNames[resource.type];
resource.amount = 100;
return resource;
}
}
磁贴类
class Tile
{
public Point location;
public Terrain terrain;
public Tile()
{
}
}
地形类
class Terrain
{
public int type;
public string name;
public int accessability;
public List<TerrainResource> resources = new List<TerrainResource>();
public Terrain()
{
}
}
地形资源类
class TerrainResource
{
public int type;
public string name;
public int amount;
public TerrainResource()
{
}
}
createTile正在调用getInstance,并导致溢出:
WPF应用程序2.exe!WpfApplication2.SimpleResourceFactory.SimpleResourceFactory() Line 116 C# WPF应用程序2.exe!WpfApplication2.SimpleTileFactory.SimpleTileFactory() Line 76 C# WPF应用程序2.exe!WpfApplication2.World.World() 第 49 行 C# WPF应用程序2.exe!WpfApplication2.World.getInstance() 第 66 行 C# WPF应用程序2.exe!WpfApplication2.SimpleTileFactory.createTile(System.Windows.Point location) 第 95 行 C# WPF应用程序2.exe!WpfApplication2.World.World() 第 56 行 C# WPF应用程序2.exe!WpfApplication2.World.getInstance() 第 66 行 C# WPF应用程序2.exe!WpfApplication2.SimpleTileFactory.createTile(System.Windows.Point location) 第 95 行 C# WPF应用程序2.exe!WpfApplication2.World.World() 第 56 行 C# WPF应用程序2.exe!WpfApplication2.World.getInstance() 第 66 行 C# WPF应用程序2.exe!WpfApplication2.SimpleTileFactory.createTile(System.Windows.Point location) 第 95 行 C#
问题是 createTile() 是在 World 构造函数中调用的。这样,当 createTile() 被执行时,World 对象还没有完全创建,然后它会调用 getInstance(),而 getInstance() 反过来又会创建一个新的世界(因为它还没有完全创建),它再次调用 createTile()。这是一个无限循环。
我做了一个快速修复,通过更改 World 构造函数和 createTile() 代码来检查它,如下所示。这不是解决它最美丽的方法,所以我可能只是将游戏资源与世界分开。
private World()
{
this.gameResources = new GameResources();
this.tileFactory = new SimpleTileFactory();
for (int i = 0; i < this.worldSize.Height; i++)
{
List<Tile> row = new List<Tile>();
for (int j = 0; j < this.worldSize.Width; j++)
{
row.Add(tileFactory.createTile(new Point(j, i), this));
}
this.tiles.Add(row);
}
}
而createTile方法:
public Tile createTile(Point location, World world)
{
//create tile
Tile tile = new Tile();
tile.location = location;
//give tile terrain type
Terrain terrain = new Terrain();
terrain.type = random.Next(0, world.gameResources.terrainNames.Count);
terrain.name = world.gameResources.terrainNames[terrain.type];
terrain.accessability = 1000;
//add resources to terrain
int numberOfResources = random.Next(0, maxNumOfResourcesPerTile + 1);
for (int i = 0; i < numberOfResources; i++)
{
terrain.resources.Add(resourceFactory.createTerrainResource(terrain.type));
}
tile.terrain = terrain;
return tile;
}