rnd - randomize numbers c#




Como posso gerar cadeias alfanuméricas aleatórias? (20)

Apenas algumas comparações de desempenho das várias respostas neste segmento:

Métodos e Configuração

// what's available
public static string possibleChars = "abcdefghijklmnopqrstuvwxyz";
// optimized (?) what's available
public static char[] possibleCharsArray = possibleChars.ToCharArray();
// optimized (precalculated) count
public static int possibleCharsAvailable = possibleChars.Length;
// shared randomization thingy
public static Random random = new Random();


// http://stackoverflow.com/a/1344242/1037948
public string LinqIsTheNewBlack(int num) {
    return new string(
    Enumerable.Repeat(possibleCharsArray, num)
              .Select(s => s[random.Next(s.Length)])
              .ToArray());
}

// http://stackoverflow.com/a/1344258/1037948
public string ForLoop(int num) {
    var result = new char[num];
    while(num-- > 0) {
        result[num] = possibleCharsArray[random.Next(possibleCharsAvailable)];
    }
    return new string(result);
}

public string ForLoopNonOptimized(int num) {
    var result = new char[num];
    while(num-- > 0) {
        result[num] = possibleChars[random.Next(possibleChars.Length)];
    }
    return new string(result);
}

public string Repeat(int num) {
    return new string(new char[num].Select(o => possibleCharsArray[random.Next(possibleCharsAvailable)]).ToArray());
}

// http://stackoverflow.com/a/1518495/1037948
public string GenerateRandomString(int num) {
  var rBytes = new byte[num];
  random.NextBytes(rBytes);
  var rName = new char[num];
  while(num-- > 0)
    rName[num] = possibleCharsArray[rBytes[num] % possibleCharsAvailable];
  return new string(rName);
}

//SecureFastRandom - or SolidSwiftRandom
static string GenerateRandomString(int Length) //Configurable output string length
{
    byte[] rBytes = new byte[Length]; 
    char[] rName = new char[Length];
    SolidSwiftRandom.GetNextBytesWithMax(rBytes, biasZone);
    for (var i = 0; i < Length; i++)
    {
        rName[i] = charSet[rBytes[i] % charSet.Length];
    }
    return new string(rName);
}

Resultados

Testado no LinqPad. Para tamanho de string de 10, gera:

  • de Linq = chdgmevhcy [10]
  • de Loop = gtnoaryhxr [10]
  • de Select = rsndbztyby [10]
  • de GenerateRandomString = owyefjjakj [10]
  • de SecureFastRandom = VzougLYHYP [10]
  • de SecureFastRandom-NoCache = oVQXNGmO1S [10]

E os números de desempenho tendem a variar um pouco, ocasionalmente NonOptimized é realmente mais rápido e, às vezes, ForLoop e GenerateRandomString alternam quem está na liderança.

  • LinqIsTheNewBlack (10000x) = 96762 tiques decorridos (9,6762 ms)
  • ForLoop (10000x) = 28970 ticks decorridos (2.897 ms)
  • ForLoopNonOptimized (10000x) = 33336 ticks decorridos (3,3366 ms)
  • Repetir (10000x) = 78547 pulsos de tempo decorridos (7.8547 ms)
  • GenerateRandomString (10000x) = 27416 tiques decorridos (2,7416 ms)
  • SecureFastRandom (10000x) = 13176 tiques decorridos (5ms) mais baixo [Máquina diferente]
  • SecureFastRandom-NoCache (10000x) = 39541 ticks decorridos (17ms) mais baixo [Máquina diferente]

Como posso gerar seqüências alfanuméricas aleatórias de 8 caracteres em c #?


Aqui está um exemplo que eu roubei do exemplo de Sam Allen no Dot Net Perls

Se você precisar apenas de 8 caracteres, use Path.GetRandomFileName () no namespace System.IO. Sam diz que usar o método "Path.GetRandomFileName aqui às vezes é superior, porque ele usa RNGCryptoServiceProvider para melhor aleatoriedade. No entanto, é limitado a 11 caracteres aleatórios."

GetRandomFileName sempre retorna uma seqüência de 12 caracteres com um período no 9º caractere. Então, você precisará despir o período (desde que não seja aleatório) e, em seguida, levar 8 caracteres da seqüência de caracteres. Na verdade, você poderia pegar os primeiros 8 caracteres e não se preocupar com o período.

public string Get8CharacterRandomString()
{
    string path = Path.GetRandomFileName();
    path = path.Replace(".", ""); // Remove period.
    return path.Substring(0, 8);  // Return 8 character string
}

PS: obrigado Sam


Eu estava procurando por uma resposta mais específica, onde eu quero controlar o formato da string aleatória e me deparei com este post. Por exemplo: placas de carros (carros) têm um formato específico (por país) e eu queria criar placas aleatórias.
Eu decidi escrever meu próprio método de extensão da Random para isso. (isto é para reutilizar o mesmo objeto Random, como você poderia ter duplas em cenários multi-threading). Eu criei uma essência ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), mas também copiei a classe de extensão aqui:

void Main()
{
    Random rnd = new Random();
    rnd.GetString("1-###-000").Dump();
}

public static class RandomExtensions
{
    public static string GetString(this Random random, string format)
    {
        // Based on http://.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings-in-c
        // Added logic to specify the format of the random string (# will be random string, 0 will be random numeric, other characters remain)
        StringBuilder result = new StringBuilder();
        for(int formatIndex = 0; formatIndex < format.Length ; formatIndex++)
        {
            switch(format.ToUpper()[formatIndex])
            {
                case '0': result.Append(getRandomNumeric(random)); break;
                case '#': result.Append(getRandomCharacter(random)); break;
                default : result.Append(format[formatIndex]); break;
            }
        }
        return result.ToString();
    }

    private static char getRandomCharacter(Random random)
    {
        string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        return chars[random.Next(chars.Length)];
    }

    private static char getRandomNumeric(Random random)
    {
        string nums = "0123456789";
        return nums[random.Next(nums.Length)];
    }
}

Eu ouvi o LINQ é o novo preto, então aqui está minha tentativa usando o LINQ:

private static Random random = new Random();
public static string RandomString(int length)
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    return new string(Enumerable.Repeat(chars, length)
      .Select(s => s[random.Next(s.Length)]).ToArray());
}

(Nota: O uso da classe Random torna isso inadequado para qualquer coisa relacionada à segurança , como a criação de senhas ou tokens. Use a classe RNGCryptoServiceProvider se precisar de um gerador forte de números aleatórios.)


Meu código de linha simples funciona para mim :)

string  random = string.Join("", Guid.NewGuid().ToString("n").Take(8).Select(o => o));

Response.Write(random.ToUpper());
Response.Write(random.ToLower());

Para expandir isso para qualquer cadeia de comprimento

    public static string RandomString(int length)
    {
        //length = length < 0 ? length * -1 : length;
        var str = "";

        do 
        {
            str += Guid.NewGuid().ToString().Replace("-", "");
        }

        while (length > str.Length);

        return str.Substring(0, length);
    }

Nós também usamos string customizada aleatoriamente, mas implementamos como auxiliar de uma string, então ela fornece alguma flexibilidade ...

public static string Random(this string chars, int length = 8)
{
    var randomString = new StringBuilder();
    var random = new Random();

    for (int i = 0; i < length; i++)
        randomString.Append(chars[random.Next(chars.Length)]);

    return randomString.ToString();
}

Uso

var random = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".Random();

ou

var random = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".Random(16);

O mais simples:

public static string GetRandomAlphaNumeric()
{
    return Path.GetRandomFileName().Replace(".", "").Substring(0, 8);
}

Você pode obter um desempenho melhor se codificar a matriz char e confiar em System.Random :

public static string GetRandomAlphaNumeric()
{
    var chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    return new string(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());
}

Se alguma vez você se preocupar, os alfabetos ingleses podem mudar em algum momento e você pode perder negócios, então você pode evitar codificação, mas deve ser um pouco pior (comparável à abordagem Path.GetRandomFileName )

public static string GetRandomAlphaNumeric()
{
    var chars = 'a'.To('z').Concat('0'.To('9')).ToList();
    return new string(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());
}

public static IEnumerable<char> To(this char start, char end)
{
    if (end < start)
        throw new ArgumentOutOfRangeException("the end char should not be less than start char", innerException: null);
    return Enumerable.Range(start, end - start + 1).Select(i => (char)i);
}

As duas últimas abordagens parecem melhores se você puder torná-las um método de extensão na instância System.Random .


Os principais objetivos do meu código são:

  1. A distribuição de strings é quase uniforme (não se preocupe com pequenos desvios, desde que sejam pequenos)
  2. Ele gera mais de alguns bilhões de strings para cada conjunto de argumentos. Gerar uma string de 8 caracteres (~ 47 bits de entropia) não tem sentido se o seu PRNG gerar apenas 2 bilhões (31 bits de entropia) de valores diferentes.
  3. É seguro, pois espero que as pessoas usem isso para senhas ou outros tokens de segurança.

A primeira propriedade é obtida tomando um módulo de valor de 64 bits no tamanho do alfabeto. Para pequenos alfabetos (como os 62 caracteres da pergunta), isso leva a um viés insignificante. A segunda e terceira propriedade são alcançadas usando RNGCryptoServiceProvider vez de System.Random .

using System;
using System.Security.Cryptography;

public static string GetRandomAlphanumericString(int length)
{
    const string alphanumericCharacters =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
        "abcdefghijklmnopqrstuvwxyz" +
        "0123456789";
    return GetRandomString(length, alphanumericCharacters);
}

public static string GetRandomString(int length, IEnumerable<char> characterSet)
{
    if (length < 0)
        throw new ArgumentException("length must not be negative", "length");
    if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody
        throw new ArgumentException("length is too big", "length");
    if (characterSet == null)
        throw new ArgumentNullException("characterSet");
    var characterArray = characterSet.Distinct().ToArray();
    if (characterArray.Length == 0)
        throw new ArgumentException("characterSet must not be empty", "characterSet");

    var bytes = new byte[length * 8];
    var result = new char[length];
    using (var cryptoProvider = new RNGCryptoServiceProvider())
    {
        cryptoProvider.GetBytes(bytes);
    }
    for (int i = 0; i < length; i++)
    {
        ulong value = BitConverter.ToUInt64(bytes, i * 8);
        result[i] = characterArray[value % (uint)characterArray.Length];
    }
    return new string(result);
}


Uma versão ligeiramente mais limpa da solução do DTB.

    var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    var random = new Random();
    var list = Enumerable.Repeat(0, 8).Select(x=>chars[random.Next(chars.Length)]);
    return string.Join("", list);

Suas preferências de estilo podem variar.


Solução 1 - maior 'intervalo' com comprimento mais flexível

string get_unique_string(int string_length) {
    using(var rng = new RNGCryptoServiceProvider()) {
        var bit_count = (string_length * 6);
        var byte_count = ((bit_count + 7) / 8); // rounded up
        var bytes = new byte[byte_count];
        rng.GetBytes(bytes);
        return Convert.ToBase64String(bytes);
    }
}

Essa solução tem mais intervalo do que usando um GUID porque um GUID tem alguns bits fixos que são sempre os mesmos e, portanto, não aleatórios, por exemplo, o caractere 13 em hexadecimal é sempre "4" - pelo menos em um GUID versão 6.

Essa solução também permite gerar uma string de qualquer tamanho.

Solução 2 - Uma linha de código - ideal para até 22 caracteres

Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 8);

Você não pode gerar strings desde que a Solução 1 e a string não tenham o mesmo intervalo devido a bits fixos em GUIDs, mas em muitos casos isso fará o trabalho.

Solução 3 - ligeiramente menos código

Guid.NewGuid().ToString("n").Substring(0, 8);

Principalmente mantendo isso aqui para fins históricos. Ele usa um pouco menos de código, embora seja o custo de ter menos alcance - porque usa hexadecimal em vez de base64, é preciso mais caracteres para representar o mesmo intervalo em comparação com as outras soluções.

O que significa mais chance de colisão - testá-lo com 100.000 iterações de 8 caracteres gera uma duplicata.


Agora no sabor de uma linha.

private string RandomName
    {
        get
        {
            return new string(
                Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                    .Select(s =>
                    {
                        var cryptoResult = new byte[4];
                        using (var cryptoProvider = new RNGCryptoServiceProvider())
                            cryptoProvider.GetBytes(cryptoResult);
                        return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                    })
                    .ToArray());
        }
    }

Aqui está uma variante da solução de Eric J, ou seja, criptograficamente som, para o WinRT (Windows Store App):

public static string GenerateRandomString(int length)
{
    var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    var result = new StringBuilder(length);
    for (int i = 0; i < length; ++i)
    {
        result.Append(CryptographicBuffer.GenerateRandomNumber() % chars.Length);
    }
    return result.ToString();
}

Se o desempenho é importante (especialmente quando o comprimento é alto):

public static string GenerateRandomString(int length)
{
    var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    var result = new System.Text.StringBuilder(length);
    var bytes = CryptographicBuffer.GenerateRandom((uint)length * 4).ToArray();
    for (int i = 0; i < bytes.Length; i += 4)
    {
        result.Append(BitConverter.ToUInt32(bytes, i) % chars.Length);
    }
    return result.ToString();
}

Se os seus valores não são completamente aleatórios, mas na verdade podem depender de algo - você pode computar um hash md5 ou sha1 daquele 'algo' e então truncá-lo para o tamanho que você quiser.

Além disso, você pode gerar e truncar um guia.


Depois de analisar as outras respostas e considerar os comentários da CodeInChaos, juntamente com a CodeInChaos, que ainda tendenciou (embora menos) a responder, achei que seria necessária uma solução definitiva de recortar e colar . Então, enquanto atualizava minha resposta, decidi fazer tudo.

Para uma versão atualizada deste código, visite o novo repositório Hg no Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . Eu recomendo que você copie e cole o código em: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&fileviewer=file-view-default (certifique-se de clicar o botão Raw para facilitar a cópia e garantir que você tenha a versão mais recente, acho que esse link vai para uma versão específica do código, não para a mais recente).

Notas atualizadas:

  1. Relacionando-se com algumas outras respostas - Se você sabe o tamanho da saída, você não precisa de um StringBuilder, e ao usar ToCharArray, isso cria e preenche a matriz (você não precisa criar uma matriz vazia primeiro)
  2. Relativo a algumas outras respostas - você deve usar NextBytes, em vez de obter um de cada vez para desempenho
  3. Tecnicamente, você pode fixar a matriz de bytes para um acesso mais rápido. Geralmente, vale a pena quando você iterar mais de 6 a 8 vezes em uma matriz de bytes. (Não feito aqui)
  4. Uso de RNGCryptoServiceProvider para melhor aleatoriedade
  5. Uso do armazenamento em cache de um buffer de dados aleatórios de 1MB - o benchmarking mostra que a velocidade de acesso de bytes únicos armazenados em cache é ~ 1000x mais rápida - levando 9ms acima de 1MB contra 989ms para não-cache.
  6. Rejeição otimizada da zona de polarização na minha nova turma.

End solution to question:

static char[] charSet =  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
public string GenerateRandomString(int Length) //Configurable output string length
{
    byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
    char[] rName = new char[Length];
    SecureFastRandom.GetNextBytesMax(rBytes, biasZone);
    for (var i = 0; i < Length; i++)
    {
        rName[i] = charSet[rBytes[i] % charSet.Length];
    }
    return new string(rName);
}

Mas você precisa da minha nova classe (não testada):

/// <summary>
/// My benchmarking showed that for RNGCryptoServiceProvider:
/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference 
/// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)
/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached
/// </summary>
class SecureFastRandom
{
    static byte[] byteCache = new byte[1000000]; //My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)
    static int lastPosition = 0;
    static int remaining = 0;

    /// <summary>
    /// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function
    /// </summary>
    /// <param name="buffer"></param>
    public static void DirectGetBytes(byte[] buffer)
    {
        using (var r = new RNGCryptoServiceProvider())
        {
            r.GetBytes(buffer);
        }
    }

    /// <summary>
    /// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance
    /// </summary>
    /// <param name="buffer"></param>
    public static void GetBytes(byte[] buffer)
    {
        if (buffer.Length > byteCache.Length)
        {
            DirectGetBytes(buffer);
            return;
        }

        lock (byteCache)
        {
            if (buffer.Length > remaining)
            {
                DirectGetBytes(byteCache);
                lastPosition = 0;
                remaining = byteCache.Length;
            }

            Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
            lastPosition += buffer.Length;
            remaining -= buffer.Length;
        }
    }

    /// <summary>
    /// Return a single byte from the cache of random data.
    /// </summary>
    /// <returns></returns>
    public static byte GetByte()
    {
        lock (byteCache)
        {
            return UnsafeGetByte();
        }
    }

    /// <summary>
    /// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache.
    /// </summary>
    /// <returns></returns>
    static byte UnsafeGetByte()
    {
        if (1 > remaining)
        {
            DirectGetBytes(byteCache);
            lastPosition = 0;
            remaining = byteCache.Length;
        }

        lastPosition++;
        remaining--;
        return byteCache[lastPosition - 1];
    }

    /// <summary>
    /// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number.
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="max"></param>
    public static void GetBytesWithMax(byte[] buffer, byte max)
    {
        if (buffer.Length > byteCache.Length / 2) //No point caching for larger sizes
        {
            DirectGetBytes(buffer);

            lock (byteCache)
            {
                UnsafeCheckBytesMax(buffer, max);
            }
        }
        else
        {
            lock (byteCache)
            {
                if (buffer.Length > remaining) //Recache if not enough remaining, discarding remaining - too much work to join two blocks
                    DirectGetBytes(byteCache);

                Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
                lastPosition += buffer.Length;
                remaining -= buffer.Length;

                UnsafeCheckBytesMax(buffer, max);
            }
        }
    }

    /// <summary>
    /// Checks buffer for bytes equal and above max. Must be called within lock of byteCache.
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="max"></param>
    static void UnsafeCheckBytesMax(byte[] buffer, byte max)
    {
        for (int i = 0; i < buffer.Length; i++)
        {
            while (buffer[i] >= max)
                buffer[i] = UnsafeGetByte(); //Replace all bytes which are equal or above max
        }
    }
}

Para a história - minha solução mais antiga para essa resposta, usei o objeto Random:

    private static char[] charSet =
      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();

    static rGen = new Random(); //Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.
    static int byteSize = 256; //Labelling convenience
    static int biasZone = byteSize - (byteSize % charSet.Length);
    static bool SlightlyMoreSecurityNeeded = true; //Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.
    public string GenerateRandomString(int Length) //Configurable output string length
    {
      byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
      char[] rName = new char[Length];
      lock (rGen) //~20-50ns
      {
          rGen.NextBytes(rBytes);

          for (int i = 0; i < Length; i++)
          {
              while (SlightlyMoreSecurityNeeded && rBytes[i] >= biasZone) //Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
                  rBytes[i] = rGen.NextByte();
              rName[i] = charSet[rBytes[i] % charSet.Length];
          }
      }
      return new string(rName);
    }

Atuação:

  1. SecureFastRandom - Primeira execução única = ~ 9-33ms . Imperceptível. Em curso : 5ms (às vezes vai até 13ms) mais de 10.000 iterações, Com uma única interação média = 1,5 microssegundos. . Nota: Requer geralmente 2, mas ocasionalmente até 8 atualizações de cache - depende de quantos bytes individuais excedem a zona de polarização
  2. Aleatório - primeira corrida única = ~ 0-1ms . Imperceptível. Em curso : 5ms mais de 10.000 iterações. Com uma única iteração média = 0,5 microssegundos. . Sobre a mesma velocidade.

Confira também:

Esses links são outra abordagem. O armazenamento em buffer poderia ser adicionado a essa nova base de código, mas o mais importante era explorar diferentes abordagens para remover o preconceito e comparar as velocidades e os prós e contras.


Eu não sei o quanto isso é criptograficamente correto, mas é mais legível e conciso do que as soluções mais complicadas de longe (imo), e deve ser mais "aleatório" do que as System.Randomsoluções baseadas.

return alphabet
    .OrderBy(c => Guid.NewGuid())
    .Take(strLength)
    .Aggregate(
        new StringBuilder(),
        (builder, c) => builder.Append(c))
    .ToString();

Não consigo decidir se acho que esta versão ou a próxima é "mais bonita", mas dão os mesmos resultados:

return new string(alphabet
    .OrderBy(o => Guid.NewGuid())
    .Take(strLength)
    .ToArray());

Concedido, não é otimizado para velocidade, por isso, se é missão crítica para gerar milhões de seqüências aleatórias a cada segundo, tente outro!

NOTA: Esta solução não permite repetições de símbolos no alfabeto, e o alfabeto deve ser de tamanho igual ou maior do que a seqüência de saída, tornando esta abordagem menos desejável em algumas circunstâncias, tudo depende do seu caso de uso.


Solução muito simples. Ele usa valores ASCII e apenas gera caracteres "aleatórios" entre eles.

public static class UsernameTools
{
    public static string GenerateRandomUsername(int length = 10)
    {
        Random random = new Random();
        StringBuilder sbuilder = new StringBuilder();
        for (int x = 0; x < length; ++x)
        {
            sbuilder.Append((char)random.Next(33, 126));
        }
        return sbuilder.ToString();
    }

}

Uma solução sem usar Random:

var chars = Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 8);

var randomStr = new string(chars.SelectMany(str => str)
                                .OrderBy(c => Guid.NewGuid())
                                .Take(8).ToArray());

public static class StringHelper
{
    private static readonly Random random = new Random();

    private const int randomSymbolsDefaultCount = 8;
    private const string availableChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    private static int randomSymbolsIndex = 0;

    public static string GetRandomSymbols()
    {
        return GetRandomSymbols(randomSymbolsDefaultCount);
    }

    public static string GetRandomSymbols(int count)
    {
        var index = randomSymbolsIndex;
        var result = new string(
            Enumerable.Repeat(availableChars, count)
                      .Select(s => {
                          index += random.Next(s.Length);
                          if (index >= s.Length)
                              index -= s.Length;
                          return s[index];
                      })
                      .ToArray());
        randomSymbolsIndex = index;
        return result;
    }
}

var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[8];
var random = new Random();

for (int i = 0; i < stringChars.Length; i++)
{
    stringChars[i] = chars[random.Next(chars.Length)];
}

var finalString = new String(stringChars);

Não é tão elegante quanto a solução Linq. (-:

(Nota: O uso da classe Random torna isso inadequado para qualquer coisa relacionada à segurança , como a criação de senhas ou tokens. Use a classe RNGCryptoServiceProvider se precisar de um gerador forte de números aleatórios.)





random