【问题标题】:List update in every loop run - Unexpected behavior每次循环运行中的列表更新 - 意外行为
【发布时间】:2014-06-27 17:04:29
【问题描述】:

我尝试编写一个模拟彩票的简单程序,但我遇到了一些我无法理解的行为,也无法修复:

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

程序:点击它应该获取用户输入的六个不同的数字(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;
    }
    

如果循环运行一次,或者每次循环后有延迟,或者我在循环中设置断点,程序就会按预期运行。

否则会出现意外行为,循环运行多次相同的数据(相同的列表),我不明白为什么。

看图片:

  1. 程序运行一次,我点击了五次按钮,显示效果很好:

(btw = Sprawdź = 检查,raz = 一次,做 pierwszej trójki = 直到 3 场比赛)

http://ultraimg.com/jHQY

  1. 当我选择直到 3 个匹配项(或单击上面代码示例中的按钮)时,我收到错误的结果,循环针对相同的值运行多次。

http://ultraimg.com/jHQn

非常感谢您的帮助,我正在学习,我知道代码的许多部分可以改进,许多部分仅用于临时调试目的。但是这种行为,我根本不明白。

【问题讨论】:

标签: c# list delay


【解决方案1】:

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

Random rndNum = new Random();

一个静态变量。

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

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

随机数生成从种子值开始。如果一样 重复使用种子,生成相同的数字序列。一 产生不同序列的方法是使种子值 时间相关,从而产生不同的系列与每个新的 随机的实例。默认情况下,无参数构造函数 Random 类使用系统时钟生成其种子值,而 它的参数化构造函数可以采用 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。

【讨论】:

  • 非常感谢!我尝试了百万种事情,没想到会这么简单。谢谢先生启发了我。
猜你喜欢
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 2017-10-04
  • 2019-04-30
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多