وظيفتي الثابتة 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" ، إلخ ..

كيف يكون هذا ممكنا؟ هو موضع تقدير كبير أي اقتراح! :-)

راجع للشغل ، نظامي: Visual Studio 2010 ، C# 4.0 ، ASP.NET MVC 3 RTM Project W/ ASP.NET Development Server. لم تختبر هذا الرمز في أي بيئات أخرى.

هل كانت مفيدة؟

المحلول

انقل الإعلان عن randomobj خارج الحلقة. عندما تقوم بتصحيحه ، فإنه يخلقه ببذور جديدة في كل مرة ، لأن هناك اختلافًا كافيًا للوقت لتكون البذور مختلفة. ولكن عندما لا تتصحيح ، فإن وقت البذور هو نفسه في الأساس لكل تكرار للحلقة ، لذلك فهو يمنحك نفس قيمة البداية في كل مرة.

و NIT ثانوي-من الجيد استخدام 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 هو قائم على الوقت, ، وعندما لا تصحح ، فإنه يطير عبر جميع التكرارات الخمسة في نفس اللحظة (أكثر أو أقل). لذلك أنت تسأل عن الرقم العشوائي الأول من نفس البذور. عندما تقوم بالتصحيح ، يستغرق وقتًا طويلاً بما يكفي للحصول على بذرة جديدة في كل مرة.

نقل إعلان Random خارج الحلقة:

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

الآن أنت المضي قدمًا على بعد 5 خطوات من بذرة عشوائية بدلاً من نقل خطوة واحدة بعيدًا عن نفس البذور العشوائية 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