C # формы: где я могу разместить генератор случайных чисел? - PullRequest
1 голос
/ 03 октября 2010

Я пытался использовать генератор случайных чисел в приложении Windows Forms, но у меня возникли проблемы с поиском, где его разместить. Мне говорят «поместите это в конструктор форм», но я не думаю, что мы говорим на одном языке. Вот код, по которому я пытаюсь найти дом:

Random rnd = new Random();
int guessMe = rnd.Next(0,100);

Но всякий раз, когда я пытаюсь разместить его вне метода клика, он говорит:

Инициализатор поля не может ссылаться нестатическое поле, метод или свойство 'LAB6B.Form1.r'

Итак, я предполагаю, что это означает, как это звучит; это должно быть внутри статического метода. Но у конструктора формы тоже нет статических методов. Может ли кто-нибудь бросить мне кость?


Вот код из Form1.cs. Сейчас я читаю какой-то другой учебник онлайн, в котором говорится, что в событии Form1_Load создается генератор случайных чисел, но я получаю ошибку контекста / области действия из события нажатия кнопки.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

    namespace LAB6B
    {

        public partial class Form1 : Form
        {


            public Form1()
            {
                InitializeComponent();            

            }

            private void Form1_Load(object sender, EventArgs e)
            {
                Random rnd = new Random();
                int guessMe = rnd.Next(0, 100);
            }

            private void btnEvaluate_Click(object sender, EventArgs e)
            {            
                int totGuesses = 0, myGuess;

                if (txtGuess.Text != "")
                {
                    myGuess = int.Parse(txtGuess.Text);
                    totGuesses++;
                    if (myGuess < guessMe)
                    {
                        btnEvaluate.Visible = false;
                        lblResult.Text = "Too Low!!";
                        lblResult.Visible = true;
                        BackColor = Color.SeaGreen;
                    }
                }

            }
        }
    }

1 Ответ

3 голосов
/ 03 октября 2010

Если вам дали этот совет, кто-то, вероятно, предлагает вам объявить переменную экземпляра, но инициализировать ее в своем конструкторе.Например:

public class Foo
{
    private readonly Random rnd;

    public Foo()
    {
        rnd = new Random();
        // Other construction code
    }
}

Тогда вы можете использовать rnd в любом месте вашего класса.

На самом деле это в основном эквивалентно:

public class Foo
{
    private readonly Random rnd = new Random();

    public Foo()
    {
        // Other construction code
    }
}

... которыйЯ в основном предпочитаю, так как это показывает, что инициализация rnd не имеет никакого отношения к каким-либо параметрам конструктора.

Поскольку кажется, что часть ваших трудностей связана с переменной guessMe, вот более полная версия:

public class Foo
{
    private readonly Random rnd = new Random();
    private int guessMe;

    public Foo()
    {
        guessMe = rng.Next(0, 100);
    }
}

Предполагается, что вам нужно, чтобы guessMe была переменной экземпляра, чтобы вы могли обращаться к ней по всему классу.С другой стороны, возможно, вам не нужна переменная Random, чтобы быть переменной экземпляра - если вы генерируете только одно случайное число, это было бы лучше, как:

public class Foo
{
    private readonly int guessMe;

    public Foo()
    {
        Random rnd = new Random();
        guessMe = rnd.Next(0, 100);
    }
}

Однако личноЯ бы не использовал ни один из этих подходов.Я бы использовал технику, которая создает один экземпляр Random для каждого потока, чтобы избежать опасностей, связанных с Random, не являющихся безопасными для потоков, и рисков, связанных с созданием двух экземпляров Random, очень близких друг к другу ввремя и заканчивая тем же семенем.

Я написал об этом достаточно много в статье на моем сайте , включая этот класс:

using System;
using System.Threading;

public static class RandomProvider
{    
    private static int seed = Environment.TickCount;

    private static ThreadLocal<Random> randomWrapper =
        new ThreadLocal<Random>(() =>
            new Random(Interlocked.Increment(ref seed))
        );

    public static Random GetThreadRandom()
    {
        return randomWrapper.Value;
    }
}

Вы можете либо использовать RandomProvider напрямую (вызывая GetThreadRandom каждый раз, когда вам нужно сгенерировать случайное число), либо вы можете передать RandomProvider.GetThreadRandom в свой класс в качестве аргумента конструктора для параметра типа Func<Random> - т.е. внедрить зависимость«Я хочу иметь возможность получить экземпляр Random в любое время».

...