我一直在研究这个程序一两个小时,每次我尝试调试它时,visual studio决定更改currentGuess.guessLine中的值,我不明白为什么。他们没有通过引用传递任何地方,他们应该更改的唯一时间是在评论'获取用户猜测'。有人可以帮忙,因为它让我疯了吗?我提供了以下代码:(我删除了任何完全不相关的方法,以缩短它。
我正在使用visual studio professional,我现在已经重写了3次这段代码,但我仍然无法弄清楚它为什么会发生。任何帮助将不胜感激。
struct History
{
public Guess[] previousGuesses;
public int noOfPreviousGuesses;
}
struct Guess
{
public int[] guessLine;
public Hint givenHint;
}
struct Hint
{
public int blackPegs;
public int whitePegs;
}
static void Main(string[] args)
{
Mastermind(3, 3);
}
static void Mastermind(int N, int M)
{
bool gameFinished;
int playAgain;
History gameHistory;
Guess currentGuess;
int[] secretCode;
do
{
//Game start
gameFinished = false;
//Reset history
gameHistory.previousGuesses = new Guess[0];
gameHistory.noOfPreviousGuesses = 0;
//Generate secretCode
secretCode = GenerateSecretCode(N, M);
do
{
//Get guess from user
currentGuess.guessLine = GetGuessLine(N, M);
//Evaluate guess
gameFinished = EvaluateGuess(currentGuess.guessLine, secretCode, N);
if (gameFinished == false)
{
//Generate hint
currentGuess.givenHint = GenerateHint(currentGuess.guessLine, secretCode, N);
//Add guess to history
gameHistory = AddGuessToHistoryQueue(currentGuess, gameHistory);
//Output history
OutputHistory(gameHistory, N);
}
} while (gameFinished == false);
//Ask to play again
playAgain = GetValueFromUser("Enter 0 or a positive value to play again, otherwise enter a negative value: ");
} while (playAgain >= 0);
}
/// <summary>
/// Gets a guess line from the user.
/// Validates each value using above procedure.
/// </summary>
/// <param name="codeLength">The length of the code being used.</param>
/// <param name="noOfColours">The number of colours allowed.</param>
/// <returns>The line entered.</returns>
static int[] GetGuessLine(int codeLength, int noOfColours)
{
int[] guessLine;
guessLine = new int[codeLength];
for (int count = 0; count < codeLength; count++)
{
//Get guessLine[count] from user
guessLine[count] = GetValueFromUserInRange(1, noOfColours, "Please enter guess at position " + count + ": ");
}
return guessLine;
}
/// <summary>
/// Compares the given guess to the given code.
/// Returns true if guess and code match exactly otherwise
/// returns false.
/// </summary>
/// <param name="guess">The guess being compared.</param>
/// <param name="code">The code to be compared against.</param>
/// <param name="codeLength">The length of the code and guess.</param>
/// <returns></returns>
static bool EvaluateGuess(int[] guess, int[] code, int codeLength)
{
bool correctGuess;
correctGuess = true;
for (int count = 0; count < codeLength; count++)
{
if (guess[count] != code[count])
{
//Found inconsistency
correctGuess = false;
break;
}
}
return correctGuess;
}
/// <summary>
/// Generates a hint through finding all matching values,
/// changing their values and incrementing the black pegs total.
/// Then calculates white pegs by checking for matching values again.
/// </summary>
/// <param name="guess">The guess requiring a hint.</param>
/// <param name="code">The code for the guess to be compared to.</param>
/// <param name="codeLength">The length of the code/guess.</param>
/// <returns>The hint generated.</returns>
static Hint GenerateHint(int[] guess, int[] code, int codeLength)
{
Hint newHint;
newHint.blackPegs = 0;
newHint.whitePegs = 0;
//Calculate blackPegs
for (int count = 0; count < codeLength; count++)
{
if (guess[count] == code[count])
{
newHint.blackPegs = newHint.blackPegs + 1;
//Hide values
guess[count] = 0;
code[count] = 0;
}
}
//Calculate white pegs
for (int guessCount = 0; guessCount < codeLength; guessCount++)
{
//Ensure current guess value hasn't been used
if (guess[guessCount] != 0)
{
//Check for matching value in code
for (int codeCount = 0; codeCount < codeLength; codeCount++)
{
if (guess[guessCount] == code[codeCount])
{
//Found match
newHint.whitePegs = newHint.whitePegs + 1;
//Hide values
guess[guessCount] = 0;
code[codeCount] = 0;
}
}
}
}
return newHint;
}
答案 0 :(得分:4)
这是许多开发人员常犯的错误。参数可以作为ByVal
或ByRef
传递(使用VB表示法)。但这样做并不是大多数人所认为的那样。
对于值类型(例如int
等 - 驻留在堆栈中的任何内容)。该值本身被复制到一个新的内存空间,并传递给该方法。因此,对值的更改不会影响原始值。
对于引用类型(例如,对象,类等 - 驻留在堆中的任何内容)。 指针被复制并传递给方法。但是,指针仍然指向内存中的同一对象。因此,对象内部属性的更改仍将反映在调用方法中。 不会唯一反映的是,如果你这样做:
myObject = new Person();
此时,传入方法的指针将被重置为指向一个全新的对象。但是来自调用方法的原始指针仍然指向原始对象。因此,它不会看到这些变化。
最容易思考的问题之一(我不是百分之百确定这是否属实,但它更容易考虑这一点)。是指针到堆中的对象并存储在堆栈中。当您设置byval
或byref
/ ref
时,它会对堆栈中的对象进行操作,而不是堆中的对象 。即Byval / ByRef 只有适用于堆。
修改强> Here是Jon Skeet支持的回答。他还链接到this文章
<强>更新强>
根据您的评论提供的其他信息。你的结构包含引用类型(int[]
是一个int数组 - 数组是引用类型),因此它们会自动移动到堆中(据我所知,至少)。
This answer从一个稍微不同的角度解决它(结构是一个类的一部分),但我认为它得到了重点