Как сгенерировать случайное число в конструкторе класса в C#
Я знаю, что не рекомендуется вызывать метод в конструкторе класса в C#, но я застрял на чем-то странном. Моя проблема в том, что когда я создаю объект своего класса, мне нужно присвоить поле в моем объекте случайное число.
например
class RandomNumberHandler
{
private int randomNumber;
public RandomNumberHandler()
{
this.randomNumber = GenerateRandomNumber();
}
private int GenerateRandomNumber()
{
return (new Random()).Next(3000) + 1000;
}
}
В моем случае мне нужен четырехзначный номер. Я думал о генерации случайного числа в классе, где я создаю объект и передаю его в качестве параметра конструктору, но генерация случайного числа в другом классе тоже не кажется хорошей идеей, потому что я пытаюсь достичь сильной сплоченности для моих занятий. Я делаю это для курса "Код высокого качества" в моем университете, и я ищу лучший подход. Любые идеи, как это сделать, приветствуются:)
5 ответов
Во-первых: нет ничего плохого в том, чтобы вызывать не виртуальные методы в конструкторе. Где ты прочитал что там было? (Примечание: вызов виртуальных методов может быть проблемой; это не автоматический нет-нет, но вам нужно очень внимательно следить за тем, что вы делаете).
Кроме того, кажется, расточительно генерировать новый Random
экземпляр каждый раз GenerateRandomNumber
называется. Вы можете извлечь Random
экземпляр для поля, чтобы исправить это:
class RandomNumberHandler
{
private readonly Random random = new Random();
private int randomNumber;
public RandomNumberHandler()
{
this.randomNumber = GenerateRandomNumber();
}
private int GenerateRandomNumber()
{
return this.random.Next(3000) + 1000;
}
}
Но это поднимает другой вопрос: если GenerateRandomNumber
вызывается только один раз за время жизни каждого экземпляра (в конструкторе), тогда не имеет смысла создавать новый Random
для каждого объекта. Итак, следующий логический шаг - сделать random
быть static
, Это означает, что GenerateRandomNumber
также может стать static
(и действительно, это должно)
class RandomNumberHandler
{
private static readonly Random Random = new Random();
private int randomNumber;
public RandomNumberHandler()
{
this.randomNumber = GenerateRandomNumber();
}
private static int GenerateRandomNumber()
{
return Random.Next(3000) + 1000;
}
}
Этот код будет работать нормально, за исключением того, что вы, скорее всего, получите "то же самое" случайное число, если вы наберете его в быстрой последовательности.
Конечно, вы можете легко обойти это, используя статическое случайное число (с блокировкой для безопасности потоков, если вы используете несколько потоков), например:
class RandomNumberHandler
{
private static Random random = new Random();
private static object syncObj = new object();
private int randomNumber;
public RandomNumberHandler()
{
this.randomNumber = GenerateRandomNumber();
}
private static int GenerateRandomNumber()
{
lock(syncObj)
return random.Next(3000) + 1000;
}
}
Генератор случайных чисел, генерирующий только одно случайное число
Краткий ответ: вы должны использовать один и тот же случайный экземпляр для всех Next()
звонки.
Если вы поднимите Random
экземпляр в качестве статического поля и сделать GenerateRandomNumber
статические, вы можете назвать это в объявлении randomNumber
поле:
class RandomNumberHandler {
private static Random random = new Random();
private int randomNumber = GenerateRandomNumber();
private static int GenerateRandomNumber() {
return random.Next(3000) + 1000;
}
}
Или более просто (и менее читабельно):
class RandomNumberHandler {
private static Random random = new Random();
private int randomNumber = random.Next(3000) + 1000;
}
Хотя это не похоже на то, что вы вызываете метод в конструкторе, если вы посмотрите на сгенерированный CIL, вы обнаружите, что это так.
Кроме того, если вы заботитесь о безопасности потоков, ознакомьтесь с этой статьей.
Я не вижу здесь никакой сплоченности, просто заключая класс Random в другой класс с именем RandomHandler. Лично я думаю, что это неловко. Если вам нужен совершенно новый случайный номер, просто вызовите Random().Next(3000) или что-то еще внутри конструктора, как вы сказали.