2014-02-22 74 views
1

我一直在研究这个程序好一两个小时,现在每次我尝试调试它时,visual studio正在决定更改currentGuess.guessLine中的值,我不知道为什么。他们没有通过引用传递任何地方,他们应该改变的唯一时间是在“来自用户的猜测”评论之下。有人能帮助,因为它让我疯狂?我已经提供了下面的代码:(我已经删除了任何完全不相关的方法,使其更短)Visual Studio传递变量作为参考?

我正在使用visual studio专业版,并且我已经重写了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; 
    } 
+1

点'INT []'是引用类型,所以通过'INT []'由值只是传递对同一个数组的引用。它不会复制数组的元素。 – hvd

+0

我的猜测是,因为你只有一个struct currentGuess引用,你修改了这个值,这可能会导致一个问题。你能解释一下你正在经历什么,因为你对症状的解释有点含糊。记住,即使结构是一个值类型,你仍然持有对你正在修改的主游戏循环中的结构的引用 – Charleh

+0

如果我错了,请原谅我,我的C#知识不是很好,但可以当你将猜测行传递给GenerateHint函数时,它正在传递我的引用,就像在C/C++中传递数组指针一样?我注意到你正在设置该函数中的[count] = 0。 – Mrfence97

回答

4

这是一个常见的错误很多开发商做。参数可为ByValByRef(用VB表示法)进行传递。但是,这样做是不正是大多数人假设它的确如此

对于值类型(例如int等 - 任何驻留在堆栈中的东西)。该值本身被复制到一个新的内存空间中,并传入该方法。因此,对该值的更改不会影响原始值。

对于引用类型(例如对象,类等 - 驻留在堆中的任何东西)。 指针被复制并传入该方法。但是,指针仍然是指向内存中的同一个对象。因此,对象内部属性的更改仍会反映在调用方法中。这不会反映的唯一的事情,就是如果你这样做:

myObject = new Person(); 

在这一点上,传递到方法的指针会被重置为指向一个全新的对象。但是来自调用方法的原始指针仍然是指向原始对象。因此它不会看到这些变化。

想到的最简单的事情之一(如果这是真的,我不是100%确定的,但它可以更容易地考虑这一点)。是指针到堆中的对象并存储在堆栈中。当您设置byvalbyref/ref时,此操作将作用于堆栈中的对象,而不是堆中的对象。即Byval/ByRef 只有适用于堆。

编辑 Here是Jon Skeet支持的答案。他还链接到this文章

更新

根据您的评论附加信息。你的结构包含引用类型(int[]是一个ints数组 - 数组是引用类型),所以它们自动移动到堆中(据我所知,至少)。

This answer铲球它从略微不同的角度(结构是一个类的一部分),但我认为它得到跨

+1

嗨,谢谢,为了您的快速响应。好吧,我明白你来自哪里。有没有办法解决这个问题? – Sciprios

+0

您可以修改代码,将传入对象中的值读入局部变量,然后对该局部变量执行操作。 –

+0

但是根据[Microsoft:](http://msdn.microsoft.com/en-us/library/8b0bdca4.aspx)虽然我的代码运行方式不同,但不通过引用传递结构体? – Sciprios