每次循环运行中的列表更新 - 意外行为

时间:2014-06-27 17:04:29

标签: c# list delay

我试着写一个简单的程序,模拟抽奖,我得到了一些我无法理解的行为,也没有解决:

为了简单起见,我排除了与问题无关的代码

程序:点击它应该获得用户输入的六个不同的数字(1到49之间),得到六个不同的随机数(1到49之间)比较它们并重复获取随机数并与输入进行比较直到有三个匹配

  1. 什么是相关的,我在按钮点击时调用函数GetResults()并传递给它两个参数(下面的方法定义)。我简化它按钮点击向您显示。那里有一些条件和函数调用,但它们正在工作,即使没有它们也存在问题,所以这就是为什么底部的图像示例可能会有所不同。

    private void btnCheck_Click(object sender, EventArgs e)
    {
        lotto.GetResults(3, ref listRndNumLabels);
    
        lblMatches.Text = lotto.CurrentMatches.ToString();
        lblTryCounter.Text = lotto.NumberOfTries.ToString();
        lblBalance.Text = lotto.Balance.ToString() + " zł";
        lblThreesAmmount.Text = lotto.ThreesAmmount.ToString();
        lblFoursAmmount.Text = lotto.FoursAmmount.ToString();
        lblFivesAmmount.Text = lotto.FivesAmmount.ToString();
        lblSixesAmmount.Text = lotto.SixesAmmount.ToString();
    }
    
  2. 方法GetResults()需要3作为所需匹配项和最后更新的标签列表

    public void GetResults(int Choice, ref List<Label> listLblRndNum)
    {
        _currentMatches = 0;
        int desiredNumberOfMatches = Choice;
    
        // while we got other ammount of matches than three, go again
        while (_currentMatches != desiredNumberOfMatches)
        {
            _numberOfTries++;
    
            // get list of mutually exclusive 6 numbers betweeen 1 and 49
            var tempList = GetRndNums();
    
            // insert random numbers to list
            _listLotteryNumbers.Clear();
            for (int i = 0; i < 6; i++)
            {
                _listLotteryNumbers.Insert(i, tempList[i]);
            }
    
            _balance -= _ticketCost;
            _currentMatches = 0;
    
            // get number of matches
            for (int i = 0; i < 6; i++)
            {
                foreach (int num in _listLotteryNumbers)
                {
                    if (_listSelectedNumbers[i] == num)
                    {
                        _currentMatches++;
                    }
                }
            }
    
            //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - _currentMatches: " + _currentMatches.ToString());
    
            //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - tempList { " + tempList[0] + " " + tempList[1] + " " + tempList[2] + " " + tempList[3] + " " + tempList[4] + " " + tempList[5] + " }");
            //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - _listLotteryNumbers { " + _listLotteryNumbers[0] + " " + _listLotteryNumbers[1] + " " + _listLotteryNumbers[2] + " " + _listLotteryNumbers[3] + " " + _listLotteryNumbers[4] + " " + _listLotteryNumbers[5] + " }");
            //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - _listSelectedNumbers { " + _listSelectedNumbers[0] + " " + _listSelectedNumbers[1] + " " + _listSelectedNumbers[2] + " " + _listSelectedNumbers[3] + " " + _listSelectedNumbers[4] + " " + _listSelectedNumbers[5] + " }");
    
            // update stats
            if (_currentMatches == 3)
            {
                _threesAmmount++;
                _balance += 10;
            }
            else if (_currentMatches == 4)
            {
                _foursAmmount++;
                _balance += 100;
            }
            else if (_currentMatches == 5)
            {
                _fivesAmmount++;
                _balance += 3500;
            }
            else if (_currentMatches == 6)
            {
                _sixesAmmount++;
                _balance += 1000000;
            }
    
            //FrmLotto.lbResults.Items.Add(_numberOfTries.ToString() + " - Threes Ammount right after updating: " + _threesAmmount);
            //FrmLotto.lbResults.Items.Add("");
    
            // this gets out of the loop if user has chosen from ddl to run once, it is irrelevant here
            if (desiredNumberOfMatches == -1)
                break;
        }
    
        // finally update Labels with the desired result
        for (int i = 0; i < 6; i++)
        {
            listLblRndNum[i].Text = _listLotteryNumbers[i].ToString();
        }
    }
    
  3. 这是获取随机数的函数:

    public List<int> GetRndNums()
    {
        List<int> listRndNums = new List<int>();
        Random rndNum = new Random();
    
        for (int i = 0; i < 6; i++)
        {
            int myNum = 0;
            do
                myNum = rndNum.Next(1, 49);
            while (listRndNums.Contains(myNum));
    
            listRndNums.Add(myNum);
        }
        listRndNums.Sort();
    
        return listRndNums;
    }
    
  4. 如果循环运行一次,或者每次循环后有延迟,或者我在循环中放置断点,那么程序按预期工作。

    另外,有一个意外的行为,对同一个数据循环运行不止一次(对于相同的列表),我不明白为什么。

    看图片:

    1. 程序运行一次,我点击了五次按钮,向您显示结果正常:
    2. (btw =Sprawdź= Check,raz = once,dopierwszejtrójki= 3场比赛)

      http://ultraimg.com/jHQY

      1. 当我选择直到3个匹配(或从上面的代码示例中单击按钮)时,我收到错误的结果,循环运行多次以获得相同的值。
      2. http://ultraimg.com/jHQn

        非常感谢您的帮助,我正在学习,我知道代码的许多部分都可以改进,很多部分仅用于临时调试目的。但是这种行为,我根本就没有得到它。

1 个答案:

答案 0 :(得分:0)

为了解决这个问题,你应该尝试制作

Random rndNum = new Random();

静态变量。

看到这个: http://msdn.microsoft.com/en-us/library/system.random.aspx

  

从一组有限的数字中以相等的概率选择伪随机数。所选择的数字不是完全随机的,因为使用确定的数学算法来选择它们,但是出于实际目的它们是足够随机的。 Random类的当前实现基于Donald E. Knuth的减法随机数生成器算法。有关更多信息,请参阅D. E. Knuth。 “计算机编程的艺术,第2卷:半数值算法”。 Addison-Wesley,Reading,MA,第二版,1981年。

     

随机数生成从种子值开始。如果相同   种子被重复使用,生成相同的数字序列。一   产生不同序列的方法是制作种子价值   与时间有关,从而与每个新系列产生不同的系列   随机的实例。默认情况下,无参数构造函数   随机类使用系统时钟生成其种子值,而   它的参数化构造函数可以取基于的Int32值   当前时间的刻度数。但是,因为时钟已经   有限分辨率,使用无参数构造函数创建   紧密连续的不同随机对象创建随机数   产生相同随机数序列的生成器。该   下面的例子说明了两个Random对象   紧密连续实例化生成一系列相同的   随机数。

byte[] bytes1 = new byte[100];
byte[] bytes2 = new byte[100];
Random rnd1 = new Random();
Random rnd2 = new Random();

rnd1.NextBytes(bytes1);
rnd2.NextBytes(bytes2);

Console.WriteLine("First Series:");
for (int ctr = bytes1.GetLowerBound(0); 
     ctr <= bytes1.GetUpperBound(0); 
     ctr++) { 
   Console.Write("{0, 5}", bytes1[ctr]);
   if ((ctr + 1) % 10 == 0) Console.WriteLine();
} 
Console.WriteLine();
Console.WriteLine("Second Series:");        
for (int ctr = bytes2.GetLowerBound(0);
     ctr <= bytes2.GetUpperBound(0);
     ctr++) {
   Console.Write("{0, 5}", bytes2[ctr]);
   if ((ctr + 1) % 10 == 0) Console.WriteLine();
}   
// The example displays the following output to the console: 
//       First Series: 
//          97  129  149   54   22  208  120  105   68  177 
//         113  214   30  172   74  218  116  230   89   18 
//          12  112  130  105  116  180  190  200  187  120 
//           7  198  233  158   58   51   50  170   98   23 
//          21    1  113   74  146  245   34  255   96   24 
//         232  255   23    9  167  240  255   44  194   98 
//          18  175  173  204  169  171  236  127  114   23 
//         167  202  132   65  253   11  254   56  214  127 
//         145  191  104  163  143    7  174  224  247   73 
//          52    6  231  255    5  101   83  165  160  231 
//        
//       Second Series: 
//          97  129  149   54   22  208  120  105   68  177 
//         113  214   30  172   74  218  116  230   89   18 
//          12  112  130  105  116  180  190  200  187  120 
//           7  198  233  158   58   51   50  170   98   23 
//          21    1  113   74  146  245   34  255   96   24 
//         232  255   23    9  167  240  255   44  194   98 
//          18  175  173  204  169  171  236  127  114   23 
//         167  202  132   65  253   11  254   56  214  127 
//         145  191  104  163  143    7  174  224  247   73 
//          52    6  231  255    5  101   83  165  160  231   
  

通过创建单个Random对象可以避免此问题   而不是多个。要提高性能,请创建一个Random对象   随着时间的推移生成许多随机数,而不是重复   创建一个新的Random对象以生成一个随机数。至   生成适合的加密安全随机数   例如,创建随机密码,使用派生自的类   System.Security.Cryptography.RandomNumberGenerator等   System.Security.Cryptography.RNGCryptoServiceProvider。