请解释一下C#的行为。引用

时间:2015-05-26 14:54:12

标签: c# object reference

我有一个带有一个参数的方法,它是我创建的类的实例 - Chessfield,它包含三个表 - 一个整数和两个bools。

在方法中我还有Chessfield列表,它是我方法的返回对象。

我正在修改chessfield(所以参考对象)并将其添加到List.Add(Chessfield)列表上几次(每次更改后一次)。

在最终返回对象中(所以列表包含Chessfield的几个对象)所有实例都是相同的,不尊重我的更改!

我已经阅读了类似的主题,并尝试将' ref'在争论之前和我进行这种方法的地方。 如果没有成功,我也尝试在方法中创建Chessfield实例,并从引用中为其分配Chessfield对象,然后对内部创建的对象进行更改。

我怎么解决?最后,我需要接收对象列表,每个对象都是从原始对象(从引用)稍微修改一下。

度过美好的一天!!

P.S。如果代码有用,那么我剪切并粘贴一般的想法代码。

编辑:

Joel undrestand me好!区别在于内部对象是表,它使问题更复杂,因为与这个原始对象相比,我在这些表中做了一些更改。为了更清楚,我粘贴了我的代码:

public class Chessfield
{

    public int[] pieces = new int[64];
    public bool[] blacks = new bool[64];
    public bool[] whites = new bool[64];

    public Chessfield(int[] pieces, bool[] blacks, bool[] whites)
    {
        this.pieces = pieces;
        this.blacks = blacks;
        this.whites = whites;
    }

    public Chessfield()
    {

    }

}

方法看起来像这样:

    static public List<Chessfield> MakeAllMovesForWhites(Chessfield chessfieldModel)
    {
        List<Chessfield> listOfPossibleMoves = new List<Chessfield>(); // list containing chessfields with changed position of figures
        int indexOfCurrentPosition = 0; //start with field 0 (most top left)

        foreach (bool singleEnemyChecker in chessfieldModel.whites) //iterate all fields,  table of whites contain information if white field stand on the field (true, otherwise false), 
        {
            if (singleEnemyChecker == true) //so algorithm will proceed only fields with white figure
            {
                int kindOfPiece = chessfieldModel.pieces[indexOfCurrentPosition]; // (table pieces contain information which kind of figure stand on particular field 0 -> empty, 1 -> soldier, 2-> tower, 3 -> horse etc...
                switch (kindOfPiece)// (based on figure at field it is going to predict all possible moves
                {

                    case 2: // tower case
                        if (indexOfCurrentPosition % 8 != 0) // check if the field is not most left, otherwise leave 
                        {
                            int localIndexIterator = indexOfCurrentPosition; //localIndex iterate all possible moves in left direction
                            while (localIndexIterator % 8 != 0) // checking if tower is standing on the most left field
                            {
                                localIndexIterator = localIndexIterator - 1; //iterate all possible moves of tower for left direction
                                if (chessfieldModel.pieces[localIndexIterator] == 0) //if there are no figures on checking field proceed:
                                {
                                    chessfieldModel.pieces[indexOfCurrentPosition] = 0; // erase tower from original position
                                    chessfieldModel.whites[indexOfCurrentPosition] = false; // and mark that white tower is not standing there anymore
                                    chessfieldModel.pieces[localIndexIterator] = 2; // put tower on new place
                                    chessfieldModel.whites[localIndexIterator] = true; // and mark that on new place there is white figure

                                    listOfPossibleMoves.Add(chessfieldModel); // here I add changed object of chessfield to list

                                    chessfieldModel.pieces[indexOfCurrentPosition] = 2; // here I come back to original chessfield
                                    chessfieldModel.whites[indexOfCurrentPosition] = true;
                                    chessfieldModel.pieces[localIndexIterator] = 0;
                                    chessfieldModel.whites[localIndexIterator] = false;
                                }
                                else //if there is figure at checking field
                                    break; //leave this case
                            }
                        }
                        if (indexOfCurrentPosition % 8 != 7) // right direction case
                        {
                          // here is similar code to the sample above
                        }
                        if (indexOfCurrentPosition / 8 != 0) //top direction case
                        {
                          // here is similar code to the sample above
                        }
                        if (indexOfCurrentPosition / 8 != 7) //bottom direction case
                        {
                          // here is similar code to the sample above
                        }
                        break;

       // here are another figures horse and so on...

                }
            }
            indexOfCurrentPosition++; // go to next field...
        }

        return listOfPossibleMoves; //return list of changed chessfields 
    }

在这里我称之为方法

Logic.MakeAllMovesForWhites(currentChessfield);

我明白这是什么问题。而乔尔 - 你解释得非常好! (y)谢谢你。

我解决问题的第一个尝试是(在我问这里之前):

Chessfield abc = new Chessfield();
abc = chessfieldModel;
abc.pieces[indexOfCurrentPosition] = 0;
abc.whites[indexOfCurrentPosition] = true;
abc.pieces[localIndexIterator] = 2;
abc.whites[localIndexIterator] = false;
listOfPossibleMoves.Add(abc);

失败。我在每种情况下都尝试过这种方法(为每个图形和每个方向创建)。顺便说一下,有33个不同的情况下,数字如何在国际象棋中移动,所以我在这33个地方上面有这段代码(但有时我把不同的东西放到桌子上......)。但是如果左边没有碎片那么像塔的图可以向左移动1,2,3,4,5,6,7个字段...这是必须创建总是新的实例的问题,我不知道怎么样,因为我必须创建唯一的实例,更改它,并添加到列表..始终是唯一的,但在不同的情况下。

此外,我已经尝试过你的解决方案Joel,但问题是我需要对原始的chessfield进行一些更改(总共4行,但不同的数字会有不同的变化)。 但我尝试创建一个新实例,将其添加到列表中,然后在列表中更改它。即便如此,没有工作和逻辑是不正确的。

listOfPossibleMoves.Add(new Chessfield() { pieces = chessfieldModel.pieces, blacks = chessfieldModel.blacks, whites = chessfieldModel.whites });
listOfPossibleMoves[listOfPossibleMoves.Count - 1].pieces[indexOfCurrentPosition] = 0;
listOfPossibleMoves[listOfPossibleMoves.Count - 1].whites[indexOfCurrentPosition] = false;
listOfPossibleMoves[listOfPossibleMoves.Count - 1].pieces[localIndexIterator] = 2;
listOfPossibleMoves[listOfPossibleMoves.Count - 1].whites[localIndexIterator] = true;
编辑:所以也许回到我的第一个方法,但我如何为在同一个地方创建的对象创建唯一的名称?你可以推荐一些技巧或在这种情况下我能做些什么吗?

感谢Joel和所有:) 每个人都度过美好的一天(或晚上)!

1 个答案:

答案 0 :(得分:2)

在问题中查看代码真的很有帮助,但听起来你正在做这样的事情:

public class ChessField 
{
   public bool b1;
   public bool b2;
   public int i1;
}

public List<ChessField> Method(ChessField c)
{
    var result = new List<ChessField>();
    for (int i = 0;i<3;i++)
    {
       c.i1 = i;
       result.Add(c);
    }
    return result;
}

问题在于:您正在将相同的对象添加到列表中。 result[0]引用相同的对象实例,result[1]引用与result[2]相同的对象实例,引用与c相同的对象实例。更改c中的属性会更改此代码中的其他位置,因为它们都是内存中相同对象的变量。如果您需要使对象不同,则必须执行某些操作来创建新的对象实例,如下所示:

public List<ChessField> Method(ChessField c)
{
    var result = new List<ChessField>();
    for (int i = 0;i<3;i++)
    {
       result.Add(new ChessField() {b1 = c.b1, b2 = c.b2, i1 = i});
    }
    return result;
}

或我喜欢的风格会这样做:

public IEnumerable<ChessField> Method(ChessField c)
{
   return Enumerable.Range(0, 3)
                    .Select(i => new ChessField() {b1 = c.b1, b2 = c.b2, i1 = i});
}