none
关于C#的静态类? RRS feed

  • 问题

  •   public partial class TestStaticClass : System.Web.UI.Page
      {
        protected void Page_Load(object sender, EventArgs e)
        {
          if(!IsPostBack)
          {
            for (int i = 0; i < 10; i++)
            {
              Image img = new Image();
              img.ImageUrl = CommonModels.GetImgPath();
              this.form1.Controls.Add(img);
            }
          }
        }
      }
    
      public static class CommonModels
      {
        public static string GetImgPath()
        {
          string[] imgPaths = new string[] 
          { 
            "/images/1335230.jpg",
            "/images/19ec261f642374e1a68669d1.jpg",
            "/images/20080921041944712.jpg",
            "/images/52821d094253afa7d0581bea.jpg",
            "/images/7ff375fcd8de833b08244d6b.gif",
            "/images/988e93cf9800777c0eb3454a.jpg"
          };
          Random r = new Random();
          int randomId = r.Next(0, imgPaths.Length);
          return imgPaths[randomId];
        }
      }
    

    为什么“在浏览器中查看”时,显示的10个照片都是一样的。而按“F5”调试的时候,显示出来的图片却不一样。

    现在真的搞不懂了,编程也有3-4年了,理论也还可以,关于静态类的概念以及它与非静态类的区别也知道,可这个问题 唉!

    2010年7月17日 2:00

答案

  • 我认为就是这个原因,没有什么说不过去的,等着你的高论吧。

    如果你对此有时间和兴趣,就去研究C#的Random随机种子生成机制吧。

    • 已标记为答案 陈书函 2010年7月19日 1:33
    2010年7月17日 10:48

全部回复

  • public partial class TestStaticClass : System.Web.UI.Page
      {
        protected void Page_Load(object sender, EventArgs e)
        {
          if(!IsPostBack)
          {
            for (int i = 0; i < 10; i++)
            {
              Image img = new Image();
              img.ImageUrl = new CommonModels().GetImgPath();
              this.form1.Controls.Add(img);
            }
          }
        }
      }
    
      public class CommonModels
      {
        public string GetImgPath()
        {
          string[] imgPaths = new string[] 
          { 
            "/images/1335230.jpg",
            "/images/19ec261f642374e1a68669d1.jpg",
            "/images/20080921041944712.jpg",
            "/images/52821d094253afa7d0581bea.jpg",
            "/images/7ff375fcd8de833b08244d6b.gif",
            "/images/988e93cf9800777c0eb3454a.jpg"
          };
          Random r = new Random();
          int randomId = r.Next(0, imgPaths.Length);
          return imgPaths[randomId];
    
          
        }
      }
    
    怎么不是静态的,在浏览器中查看,也还是10张图片都是一样的?Random 类 的问题吗?
    2010年7月17日 2:41
  • 应该和你的静态类没有关系,你应该是你在For循环执行间隔时间的问题,导致调试和运行模式不一样。

    你这样试试

     if(!IsPostBack)
          {
            for (int i = 0; i < 10; i++)
            {
              Image img = new Image();
              img.ImageUrl = new CommonModels().GetImgPath();
              this.form1.Controls.Add(img);

              System.Threading.Thread.Sleep(1000);//时间间隔
            }
          }


    http://blog.csdn.net/zx13525079024
    2010年7月17日 3:32
  • 您的说法,我测试过。

    for (int i = 0; i < 10; i++)
          {
            Random r = new Random();
            Console.WriteLine(r.Next(0,10));
          }
          Console.ReadKey();
    

     

    for (int i = 0; i < 10; i++)
          {
            Random r = new Random();
            Console.WriteLine(r.Next(0,10));
            System.Threading.Thread.Sleep(500);
          }
          Console.ReadKey();
    

    请问您知道是什么原因不?

    2010年7月17日 3:50
  • 你在“在浏览器中查看”,相当与直接运行,这样的话FOR中的循环执行非常快,每次循环几乎没有时间间隔,导致每次循环生成的随机数是一样的.

    你在调试的时候是单步执行的,存在时间间隔,生成的随机数不一样,

    你用System.Threading.Thread.Sleep(500);休眠一下,这样每次生成的随机数就不一样了


    http://blog.csdn.net/zx13525079024
    2010年7月17日 4:25
  • 恩,结果我也看到了,可是为什么For循环就会导致生产的随机数一样呢?MSDN上面有讲吗?

    2010年7月17日 4:52
  • 把Random r = new Random();做成静态的,让它只new一次。

    现在机器硬件太高级了,同一毫秒里,也许多次new所用的随机种子值一样。Sleep会导致时间改变,进而导致随机种子改变。

    2010年7月17日 6:01
  • @纪元隆 用户奖牌用户奖牌用户奖牌用户奖牌用户奖牌

    您提供的做法,我也试过了,确实能实现

          Random r = new Random();
          for (int i = 0; i < 10; i++)
          {
            Console.WriteLine(r.Next(0, 10));
          }
          Console.ReadKey();
    
    但理由:“现在机器硬件太高级了,同一毫秒里,也许多次new所用的随机种子值一样。Sleep会导致时间改变,进而导致随机种子改变。”好像有点说不过去。
    2010年7月17日 7:16
  • 我认为就是这个原因,没有什么说不过去的,等着你的高论吧。

    如果你对此有时间和兴趣,就去研究C#的Random随机种子生成机制吧。

    • 已标记为答案 陈书函 2010年7月19日 1:33
    2010年7月17日 10:48
  • 研究这个机制的资料也不少,比如:

    http://www.cnblogs.com/falla/archive/2010/01/29/1659399.html

    2010年7月17日 10:49
  • 你好!

         计算机里的随机数都是伪随机数,并非是真正的随机数,都是根据随机算法生成的,随意还是有内部的规律的。你使用这个构造函数Random r = new Random();来初始化Random实例,使用的是系统时间作为种子的,如果两次执行的间隔很短,时间是一样的。很可能产生重复的“随机数”。

         解决方法有如下几种:

         1,Random r = new Random(i)自己指定种子,这个i可以指定其他随机数,这样可以降低重复的几率。

         2,增加时间间隔。

         3,如果要求生成不重复的随机数,可以尝试:
    1,通过while循环来实现
      通过while循环不停的生成随机数,直到生成一个不重复的为止,这种方法比较容易想到,但是效率也比较低下,实例代码如下:
              static void Main(string[] args)
            {
                int[] result = new int[10];
                int tmp = -1;
                Random random = new Random();
                bool repeat = false;
                for (int i = 0; i < 10; i++)
                {
                    repeat = true;
                    while (repeat)
                    {
                        repeat = false;

                        tmp = random.Next(1, 11);
                        for (int j = 0; j < i; j++)
                        {
                            if (tmp == result[j])
                            {
                                repeat = true;
                                break;
                            }
                        }
                    }
                    result[i] = tmp;
                   

                }

                for (int i = 0; i < 10; i++)
                    Console.WriteLine(result[i].ToString());               
            }
    2,通过for循环来实现
       方法1使用了多处循环嵌套,效率十分低下,所以我应用一定的技巧来减少循环嵌套,来达到提高程序效率的目的。主要思路是如果检测到重复,就把循环变量减1,这样来重新进行一次循环,重新生成一个随机数,直到生成一个不重复的随机数为止,实例代码如下:
            static void Main(string[] args)
            {
                int[] result = new int[10];
                int tmp = -1;
                Random random = new Random();
                bool repeat = false;
                for (int i = 0; i < 10; i++)
                {
                    repeat = false;

                    tmp = random.Next(1, 11);
                    for (int j = 0; j < i; j++)
                    {
                        if (tmp == result[j])
                        {
                            repeat = true;
                            break;
                        }
                    }
                    if (!repeat)
                    {
                        result[i] = tmp;
                    }
                    else
                    {
                        i = i - 1;//循环变量-1
                    }
                   

                }

                for (int i = 0; i < 10; i++)
                    Console.WriteLine(result[i].ToString()); 
            }
        这个方法减少了一层循环嵌套,效率上有一定的改善!
    3,通过随机排序来实现
       这种方法彻底的颠覆了方法1和2的基本思路,先初始化一个包含数字1-10的数组,然后每次循环取一个随机位置,将这个位置的元素和最后一个位置的元素交换!实例代码如下:
            static void Main(string[] args)
            {
                int[] result = new int[10];
                for (int i = 0; i < 10; i++)
                    result[i] = i + 1;
                for (int j = 9; j > 0; j--)
                {
                    Random r = new Random();
                    int index = r.Next(0, j);
                    int temp = result[index];
                    result[index] = result[j];
                    result[j] = temp;
                }

                for (int i = 0; i < 10; i++)
                    Console.WriteLine(result[i].ToString());
                   
            }
    这种方法消除了循环嵌套,效率上获得了进一步的改善,但是也有一定的限制,如果要生成5个1-10之间的随机数,那这种打乱顺序的方法就无法使用了!

    总结:方法1效率比较低下,一般不推荐使用!
          方法2比较通用,效率高于方法1,但是效率低于方法3
          方法3虽然效率比较高,但是只能应用与特定的情况下!

    请大家多多指教啊!


    周雪峰
    • 已建议为答案 mazhou 2010年7月19日 8:26
    2010年7月19日 6:22
    版主
  • 除了楼上的答案之外,用 Random 生成不重复随机数的方法,只需要简单的修改为:

    Random random = new Random(System.Environment.TickCount);

    因为 CPU 每时每刻的 Tick 值都不一样,所以可以保证至少在一定时间内的结果的低重复率。这个方法是生成随机字符串的一个很好的方法。

    以下是我写的一个 RandomString 类用来生成随机字符串的,这个在 Automation Test 中非常常用。

    // --------------------------------------------------------------------------------------------------------------------
    // <copyright file="RandomHelper.cs" company="Xuenn Pte Ltd">
    // Copyright (C) 2010 Microsoft Corp, All Rights Reserved.
    // </copyright>
    // <summary>
    // Provides helper methods to generate random literals. This class is static.
    // </summary>
    // --------------------------------------------------------------------------------------------------------------------
    
    namespace Microsoft.Samples
    {
     #region Using Directives
    
     using System;
     using System.Globalization;
     using System.Text;
     using System.Threading;
    
     #endregion
    
     /// <summary>
     /// Provides helper methods to generate random literals. This class is static.
     /// </summary>
     public static class RandomHelper
     {
      #region Constants and Fields
    
      /// <summary>
      /// Stores the constant value that represents the interval between two generations in milliseconds.
      /// </summary>
      private const int DefaultGenerationInterval = 50;
    
      /// <summary>
      /// Stores the default Email format string.
      /// </summary>
      private const string EmailFormat = "{0}@{1}.{2}";
    
      /// <summary>
      /// Stores the default HTTP based URI format.
      /// </summary>
      private const string HttpUriFormat = "http://{0}.{1}.{2}";
    
      /// <summary>
      /// Stores the default top-level domain suffix.
      /// </summary>
      private static readonly string[] domainSuffix = { "com", "net", "org", "gov", "edu" };
    
      #endregion
    
      #region Public Methods
    
      /// <summary>
      /// Generates a random string that represents a valid email address.
      /// </summary>
      /// <returns>
      /// <see cref="String"/> that represents the generated random email address.
      /// </returns>
      public static string GenerateEmailAddress()
      {
       string userName = RandomHelper.GenerateString(16, StringGenerationOptions.LowercasedLetters | StringGenerationOptions.Digits);
       string domain = RandomHelper.GenerateString(16, StringGenerationOptions.LowercasedLetters | StringGenerationOptions.Digits);
      
       return string.Format(CultureInfo.CurrentCulture, RandomHelper.EmailFormat, userName, domain, RandomHelper.GenerateDomainSuffix());
      }
    
      /// <summary>
      /// Generates a random string that represents a valid HTTP URI.
      /// </summary>
      /// <returns>
      /// <see cref="String"/> that represents the generated random HTTP URI.
      /// </returns>
      public static Uri GenerateHttpUri()
      {
       string subdomain = RandomHelper.GenerateString(16, StringGenerationOptions.LowercasedLetters | StringGenerationOptions.Digits);
       string domain = RandomHelper.GenerateString(16, StringGenerationOptions.LowercasedLetters | StringGenerationOptions.Digits);
    
       return
        new Uri(
         string.Format(
          CultureInfo.CurrentCulture, 
          RandomHelper.HttpUriFormat, 
          subdomain, 
          domain, 
          RandomHelper.GenerateDomainSuffix()));
      }
    
      /// <summary>
      /// Generates a random string with the specified length.
      /// </summary>
      /// <param name="maxSize">
      /// Max size of the string to generate.
      /// </param>
      /// <param name="options">
      /// The options that is used to control the string generation.
      /// </param>
      /// <param name="additionalCondition">
      /// The expression that indicates the matched characters are included in generation.
      /// </param>
      /// <returns>
      /// <see cref="string"/> that represents the generated random string.
      /// </returns>
      /// <exception cref="ArgumentOutOfRangeException">
      /// <paramref name="maxSize"/> is less or equal to zero.
      /// </exception>
      /// <exception cref="ArgumentException">
      /// <paramref name="options"/> is set to <c>None</c>.
      /// </exception>
      public static string GenerateString(int maxSize, StringGenerationOptions options, Func<char, bool> additionalCondition)
      {
       if (maxSize < 1)
       {
        throw new ArgumentOutOfRangeException("maxSize");
       }
    
       if (options == StringGenerationOptions.None)
       {
        throw new ArgumentException(Resources.Messages.OneStringGenerationOptionsMustBeSpecified, "options");
       }
    
       StringBuilder builder = new StringBuilder();
       int tick = Environment.TickCount;
    
       // Sleep for 10 milliseconds in order to avoid the duplicate of random strings
       // generated from this time and next time.
       Thread.Sleep(RandomHelper.DefaultGenerationInterval);
       Random random = new Random(tick);
    
       for (int i = 0; i < maxSize; i++)
       {
        char c = Convert.ToChar(random.Next(128));
        bool insert = (options & StringGenerationOptions.LowercasedLetters) == StringGenerationOptions.LowercasedLetters && char.IsLower(c);
    
        insert = insert || ((options & StringGenerationOptions.UppercasedLetters) == StringGenerationOptions.UppercasedLetters && char.IsUpper(c));
        insert = insert || ((options & StringGenerationOptions.Digits) == StringGenerationOptions.Digits && char.IsDigit(c));
        insert = insert || ((options & StringGenerationOptions.WhiteSpaces) == StringGenerationOptions.WhiteSpaces && char.IsWhiteSpace(c));
        insert = insert || ((options & StringGenerationOptions.Dashes) == StringGenerationOptions.Dashes && c == '-');
        insert = insert || ((options & StringGenerationOptions.Underscores) == StringGenerationOptions.Underscores && c == '_');
        insert = insert || (additionalCondition == null ? false : additionalCondition(c));
    
        if (insert)
        {
         builder.Append(c);
        }
       }
    
       return builder.ToString();
      }
    
      /// <summary>
      /// Generates a random string with the specified length.
      /// </summary>
      /// <param name="maxSize">
      /// Max size of the string to generate.
      /// </param>
      /// <param name="options">
      /// The options that is used to control the string generation.
      /// </param>
      /// <returns>
      /// <see cref="string"/> that represents the generated random string.
      /// </returns>
      /// <exception cref="ArgumentOutOfRangeException">
      /// <paramref name="maxSize"/> is less or equal to zero.
      /// </exception>
      /// <exception cref="ArgumentException">
      /// <paramref name="options"/> is set to <c>None</c>.
      /// </exception>
      public static string GenerateString(int maxSize, StringGenerationOptions options)
      {
       return RandomHelper.GenerateString(maxSize, options, null);
      }
    
      /// <summary>
      /// Generates a random string with random 64 Unicode characters.
      /// </summary>
      /// <returns>
      /// <see cref="String"/> that represents the generated random string.
      /// </returns>
      public static string GenerateString()
      {
       return RandomHelper.GenerateString(64);
      }
    
      /// <summary>
      /// Generates a random string with specified length.
      /// </summary>
      /// <param name="maxSize">
      /// The size of the string to generate.
      /// </param>
      /// <returns>
      /// <see cref="String"/> that represents the generated random string.
      /// </returns>
      public static string GenerateString(int maxSize)
      {
       StringGenerationOptions options = StringGenerationOptions.LowercasedLetters
        | StringGenerationOptions.UppercasedLetters
        | StringGenerationOptions.Digits
        | StringGenerationOptions.WhiteSpaces
        | StringGenerationOptions.Underscores
        | StringGenerationOptions.Dashes;
    
       return RandomHelper.GenerateString(maxSize, options);
      }
    
      #endregion
    
      #region Methods
    
      /// <summary>
      /// Generates a domain suffix from a pre-defined domain suffix list.
      /// </summary>
      /// <returns>
      /// <see cref="string"/> that represents the generated domain suffix (without dot separator (".")).
      /// </returns>
      private static string GenerateDomainSuffix()
      {
       int tick = Environment.TickCount;
       Random random = new Random(tick);
       int suffixIndex = random.Next(0, RandomHelper.domainSuffix.Length - 1);
       
       // Sleep for 10 milliseconds in order to avoid the duplicate of random strings
       // generated from this time and next time.
       Thread.Sleep(RandomHelper.DefaultGenerationInterval);
    
       return RandomHelper.domainSuffix[suffixIndex];
      }
    
      #endregion
     }
    }
    

    Mark Zhou
    2010年7月19日 8:36
  • Random实例化的位置,放在静态类的构造时声明一次就对了。

    public static class CommonModels

    {

        static Random Random;

        static CommonModels()
       {
              Random = new Random();
        }

        ...

    }

     

     

    2010年7月28日 7:06