وظيفتي الثابتة C# تلعب الألعاب معي ... غريبة تمامًا!
-
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 ، لذلك يجب أن يتصرف أكثر مثل مصدر الانتروبيا. إذا كنت بحاجة إلى التكرار للاختبار ، فاستخدم الحمل الزائد للمركيب العشوائي الذي يتيح لك تزويد البذور. نفس البذور == نفس تسلسل العشوائي الزائفة.