Моя статическая функция C # играет в игры со мной ... Головки странно!

StackOverflow https://stackoverflow.com/questions/4800010

  •  26-09-2019
  •  | 
  •  

Вопрос

Итак, я написал маленький и, от того, что я изначально подумал, легкий метод в C #. Этот статический метод предназначен для использования в качестве простого генератора предложения пароля, а код выглядит следующим образом:

public static string CreateRandomPassword(int outputLength, string source = "")
{
  var output = string.Empty;

  for (var i = 0; i < outputLength; i++)
  {
     var randomObj = new Random();
     output += source.Substring(randomObj.Next(source.Length), 1);
  }

  return output;
}

Я называю эту функцию, как это:

var randomPassword = StringHelper.CreateRandomPassword(5, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");

Теперь этот метод почти всегда возвращает случайные строки, такие как «AAAAAA», «BBBBBB», «888888» и т. Д .., где я думал, что он должен возвращать строки, такие как «A8JK2A», «82MOK7» и т. Д.

Однако и вот странная часть; Если я помещу точку останова, и выйдите через эту линию итерации по строке, я получаю правильный тип пароля в ответ. В 100% других случаев, когда я не отладки, это дает мне дерьмо, как «AAAAAA», «666666», и т. Д.

Как это возможно? Любое предложение очень ценится! :-)

BTW, Моя система: Visual Studio 2010, C # 4.0, ASP.NET MVC 3 RTM Project W / ASP.NET Development Server. Не проверил этот код в любых других средах.

Это было полезно?

Решение

Переместите объявление для Randomobj за пределами петли. Когда вы отладки его, это создает его с новым семенем каждый раз, потому что есть достаточно разницы с временем для семян, чтобы быть другим. Но когда вы не отладки, время семена в основном одинаково для каждой итерации цикла, поэтому он дает вам одно и то же значение запуска каждый раз.

И несовершеннолетний НИТ - это хорошая привычка использовать StringBuilder, а не строку для этой вещи, поэтому вам не нужно повторно инициализировать пространство памяти каждый раз, когда вы добавляете символ в строку.

Другими словами, как это:

public static string CreateRandomPassword(int outputLength, string source = "")
{
  var output = new StringBuilder();
  var randomObj = new Random();
  for (var i = 0; i < outputLength; i++)
  {
     output.Append(source.Substring(randomObj.Next(source.Length), 1));
  }
  return output.ToString();
}

Другие советы

Поведение, которое вы видите, это потому, что Random является по времени, И когда вы не отладки, он летит через все 5 итераций в тот же момент (более или менее). Таким образом, вы просите первое случайное число от того же семени. Когда вы отладки, это достаточно долго, чтобы получить новое семя каждый раз.

Переместить декларацию Random За пределами петли:

var randomObj = new Random();
for (var i = 0; i < outputLength; i++)
{
    output += source.Substring(randomObj.Next(source.Length), 1);
}

Теперь ты двигаться вперед в 5 шагах от случайного семени вместо Перемещение 1 шаг от того же случайного семян 5 раз.

Вы создаете новый экземпляр случайных () на каждой итерации через петлю с новым семенным зависимым от времени. Учитывая гранулярность системных часов и скорости современных процессоров, это почти гарантирует, что вы перезапускаете псевдослучайную последовательность снова и снова с тем же сеемкой.

Попробуйте что-то вроде следующего, хотя, если вы можете заблокировать, вы можете безопасно пропустить замок ():

private static Random randomBits = new Random() ;
public static string CreateRandomPassword(int outputLength, string source = "")
{
  StringBuilder sb = new StringBuilder(outputLength) ;
  lock ( randomBits )
  {
    while ( sb.Length < outputLength )
    {
      sb.Append( randomBits.Next( source.Length) , 1 ) ;
    }
  }
  return sb.ToString() ;
}

Вы только что разумлите RNG один раз. Каждый рисует биты из того же RNG, поэтому он должен вести себя гораздо больше похоже на источник энтропии. Если вам нужна повторяемость для тестирования, используйте случайную перегрузку конструктора, которая позволяет вам поставлять семена. Те же семена == же псевдослучайная последовательность.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top