在一个对象被另一个对象引用后初始化它

本文关键字:初始化 对象引用 另一个 一个对象 | 更新日期: 2023-09-27 18:07:58

我有一个二维数组,它存储了一个棋盘的字段。

private field[,] board = new field[boardsize,boardsize];

. .现在,当我初始化它们时,我想引用每个字段的邻居,它们部分还没有初始化。

现在我们使用这样的解决方法:

for(int x = 0; x < boardsize ; x++)
{
  for(int y = 0; y < boardsize ; y++)
  {
    board[x,y] = new field();
  }
}

for(int x = 0; x < boardsize ; x++)
{
  for(int y = 0; y < boardsize ; y++)
  {
    board[x,y].setNeighbours(x, y, board);
  }
}

这工作得很好,但我感兴趣的是是否可以在初始化之前或在初始化时设置邻居。

setNeighbour - Method:

setNeighbour(int x, int y, field[,])
{
  if(field[x-1,y] != null)
    this.neighbour[0] = field[x-1,y];
  if(field[x-1,y+1] != null)
    this.neighbour[0] = field[x-1,y+1];
  if(field[x,y+1] != null)
    this.neighbour[0] = field[x,y+1];
  if(field[x+1,y+1] != null)
    this.neighbour[0] = field[x+1,y+1];
  if(field[x+1,y] != null)
    this.neighbour[0] = field[x+1,y];
  if(field[x+1,y-1] != null)
    this.neighbour[0] = field[x+1,y-1];
  if(field[x,y-1] != null)
    this.neighbour[0] = field[x,y-1];
  if(field[x-1,y-1] != null)
    this.neighbour[0] = field[x-1,y-1];
}

在一个对象被另一个对象引用后初始化它

你可以这样做:

private field[,] board = new field[boardsize,boardsize];
for(int x = 0; x < boardsize ; x++)
{
  for(int y = 0; y < boardsize ; y++)
  {
    if(board[x,y] == null)
        board[x,y] = new field();
    board[x,y].setNeighbours(x, y, board);
  }
}

和检查setNeighbours()方法中邻居初始化的方法相同:

private void setNeighbours(int x, int y, field[,] board)
{
    //Initialize neighbour if not already initialized
    if(board[x+1,y] == null)
       board[x+1,y] = new field();
    //DO SOMETHING... 
}

我不相信这是可能的引用邻居,因为他们还没有创建。但是,您可以将board作为字段的构造函数的参数添加,并在以后需要时使用属性来查找邻居。

这是一个经典问题…遗憾的是c#没有延续…它们可以通过使用Thread来模拟(非常缓慢)。是的,这是多余的,这只是编程中的一个练习:

public sealed class WaitForReady<T> : IDisposable
{
    public readonly ManualResetEvent mre = new ManualResetEvent(false);
    public T Value
    {
        get
        {
            mre.WaitOne();
            return this.value;
        }
        set
        {
            this.value = value;
            mre.Set();
        }
    }
    private T value;
    #region IDisposable Members
    public void Dispose()
    {
        mre.Dispose();
    }
    #endregion
}
public class Field
{
    public Field[] Neighbours;
    public Field(WaitForReady<Field> me, WaitForReady<Field>[] neighbours)
    {
        me.Value = this;
        Neighbours = new Field[neighbours.Length];
        for (int i = 0; i < neighbours.Length; i++)
        {
            Neighbours[i] = neighbours[i] != null ? neighbours[i].Value : null;
        }
    }
}
public static void Main(string[] args)
{
    int boardsize = 8;
    Field[,] board = new Field[boardsize, boardsize];
    WaitForReady<Field>[,] boardTemp = null;
    try
    {
        boardTemp = new WaitForReady<Field>[boardsize, boardsize];
        var threads = new Thread[boardsize * boardsize];
        for (int i = 0; i < boardsize; i++)
        {
            for (int j = 0; j < boardsize; j++)
            {
                boardTemp[i, j] = new WaitForReady<Field>();
            }
        }
        int k = 0;
        for (int i = 0; i < boardsize; i++)
        {
            for (int j = 0; j < boardsize; j++)
            {
                var neighbours = new WaitForReady<Field>[8];
                neighbours[0] = i > 0 && j > 0 ? boardTemp[i - 1, j - 1] : null;
                neighbours[1] = i > 0 ? boardTemp[i - 1, j] : null;
                neighbours[2] = i > 0 && j + 1 < boardsize ? boardTemp[i - 1, j + 1] : null;
                neighbours[3] = j > 0 ? boardTemp[i, j - 1] : null;
                neighbours[4] = j + 1 < boardsize ? boardTemp[i, j + 1] : null;
                neighbours[5] = i + 1 < boardsize && j > 0 ? boardTemp[i + 1, j - 1] : null;
                neighbours[6] = i + 1 < boardsize ? boardTemp[i + 1, j] : null;
                neighbours[7] = i + 1 < boardsize && j + 1 < boardsize ? boardTemp[i + 1, j + 1] : null;
                int i1 = i, j1 = j;
                threads[k] = new Thread(() => board[i1, j1] = new Field(boardTemp[i1, j1], neighbours));
                threads[k].Start();
                k++;
            }
        }
        // Wait for all the threads
        for (int i = 0; i < threads.Length; i++)
        {
            threads[i].Join();
        }
    }
    finally
    {
        // Dispose the WaitForReady
        if (boardTemp != null)
        {
            for (int i = 0; i < boardsize; i++)
            {
                for (int j = 0; j < boardsize; j++)
                {
                    if (boardTemp[i, j] != null)
                    {
                        boardTemp[i, j].Dispose();
                    }
                }
            }
        }
    }
}

这里的"技巧"是在64个单独的线程中创建Field。当初始化时,Field首先向每个人"宣布"自己(通过设置其相应的WaitForReady<>对象),然后它向其邻居请求其this引用。它通过作为参数接收的WaitForReady<>对象来实现这一点。WaitForReady<>是一个"特殊的"容器,它可以包含单个值(Value)。如果没有设置Value,那么请求它将使线程处于等待状态,直到有人通过set设置该值。

对于小尺寸,可以使用递归来模拟延续来构建所有东西。对于64的棋盘大小,这通常是可能的。这样比较快。

public class Field
{
    public Field[] Neighbours;
    public Field(int i, int j, int boardsize, Func<Field>[,] getters)
    {
        Console.WriteLine("Building [{0},{1}]", i, j);
        getters[i, j] = () => this;
        Neighbours = new Field[8];
        Neighbours[0] = i > 0 && j > 0 ? getters[i - 1, j - 1]() : null;
        Neighbours[1] = i > 0 ? getters[i - 1, j]() : null;
        Neighbours[2] = i > 0 && j + 1 < boardsize ? getters[i - 1, j + 1]() : null;
        Neighbours[3] = j > 0 ? getters[i, j - 1]() : null;
        Neighbours[4] = j + 1 < boardsize ? getters[i, j + 1]() : null;
        Neighbours[5] = i + 1 < boardsize && j > 0 ? getters[i + 1, j - 1]() : null;
        Neighbours[6] = i + 1 < boardsize ? getters[i + 1, j]() : null;
        Neighbours[7] = i + 1 < boardsize && j + 1 < boardsize ? getters[i + 1, j + 1]() : null;
        Console.WriteLine("Builded [{0},{1}]", i, j);
    }
}
public static void Main(string[] args)
{
    int boardsize = 8;
    Field[,] board = new Field[boardsize, boardsize];
    Func<Field>[,] getters = new Func<Field>[boardsize, boardsize];
    for (int i = 0; i < boardsize; i++)
    {
        for (int j = 0; j < boardsize; j++)
        {
            int i1 = i, j1 = j;
            getters[i, j] = () => board[i1, j1] = new Field(i1, j1, boardsize, getters);
        }
    }
    for (int i = 0; i < boardsize; i++)
    {
        for (int j = 0; j < boardsize; j++)
        {
            getters[i, j]();
        }
    }
}

另一种方法是让Fields处理其他字段的创建。写所有的代码要做更多的工作,但它应该更有效率。

结果是你不能在构造函数中这样做,因为你会进入一个试图创建彼此的字段的无限循环(因为它们还不能找到彼此)。

我喜欢做像积极内联这样的事情,即使它在发布模式下只会产生微小的差异,实际上在调试模式下会减慢代码的速度。在我的机器上,1万次执行大约需要0.1秒。我很想知道这是否比@xanatos的答案快。P

using System.Runtime.CompilerServices;
namespace Algorithms
{
    public class Board
    {
        public Field[,] fields = new Field[8, 8];
    }
    public class Field
    {
        // Neighbor positions
        // 701  +1-1 +10  +1+1 
        // 6 2   0-1  00   0+1
        // 543  -1-1 -10, -1+1
        private Field[] neighbors = new Field[8];
        public void FindNeighbors(Board board, int rank, int file)
        {
            if (rank > 0)
            {
                // Not on bottom
                createNeighbor(board, rank - 1, file, 4);
                if (file > 0)
                {
                    // Not in bottom-left corner, so adding it
                    //createNeighbor(board, rank - 1, file, 4);
                    createNeighbor(board, rank - 1, file - 1, 5);
                    createNeighbor(board, rank, file - 1, 6);
                    if (rank < 7)
                    {
                        // Not on top corner, so adding above and left-above
                        createNeighbor(board, rank + 1, file - 1, 7);
                        createNeighbor(board, rank + 1, file, 0);
                        if (file < 7)
                        {
                            // Not in any corder, adding remainder
                            createNeighbor(board, rank, file + 1, 2);
                            createNeighbor(board, rank - 1, file + 1, 3);
                            createNeighbor(board, rank + 1, file + 1, 1);
                        }
                        else
                        {
                            // On the right, the only fields that haven't been added yet are on the right
                        }
                    }
                    else
                    {
                        // on top
                        if (file < 7)
                        {
                            // Not on the left, so add those fields.
                            createNeighbor(board, rank, file + 1, 2);
                            createNeighbor(board, rank - 1, file + 1, 3);
                        }
                        else
                        {
                            // On the top-left, so nothing else to add.
                        }
                    }
                }
                else
                {
                    createNeighbor(board, rank, file + 1, 2);
                    createNeighbor(board, rank - 1, file + 1, 3);
                    if (rank < 7)
                    {
                        createNeighbor(board, rank + 1, file, 0);
                        createNeighbor(board, rank + 1, file + 1, 1);
                    }
                    else
                    {
                        // Top-left corner, nothing to add
                    }
                }
            }
            else
            {
                // Bottom
                createNeighbor(board, rank + 1, file, 0);
                if (file > 0)
                {
                    // Not on left
                    createNeighbor(board, rank, file - 1, 6);
                    createNeighbor(board, rank + 1, file - 1, 7);
                    if (file < 7)
                    {
                        // Not on the right
                        createNeighbor(board, rank + 1, file + 1, 1);
                        createNeighbor(board, rank, file + 1, 2);
                    }
                }
                else
                {
                    // Bottom-left corner
                    createNeighbor(board, rank + 1, file + 1, 1);
                    createNeighbor(board, rank, file + 1, 2);
                }
            }
        }
        // Neighbor positions
        // 701  +1-1 +10  +1+1 
        // 6 2   0-1  00   0+1
        // 543  -1-1 -10, -1+1
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void createNeighbor(Board board, int rank, int file, int neighbor)
        {
            var field = board.fields[rank, file];
            if (field == null)
            {
                field = new Field();
                board.fields[rank, file] = field;
                // Start looking for neighbors after their object is initialized.
                field.FindNeighbors(board, rank, file);
            }
            // Always copy a link to the field, even if it already existed
            neighbors[neighbor] = field;
        }
    }
}