web-dev-qa-db-fra.com

Identifiant unique abrégé .NET

J'ai besoin d'un identifiant unique dans .NET (je ne peux pas utiliser GUID car il est trop long pour ce cas).

Les gens pensent-ils que l'algorithme utilisé ici est un bon candidat ou avez-vous d'autres suggestions?

61
Noel

Celui-ci un bon - http://www.singular.co.nz/blog/archive/2007/12/20/shortguid-a-shorter-and-url-friendly-guid-in-c-sharp. aspx

et aussi ici YouTube-like GUID

Vous pouvez utiliser Base64:

string base64Guid = Convert.ToBase64String(Guid.NewGuid().ToByteArray());

Cela génère une chaîne comme E1HKfn68Pkms5zsZsvKONw ==. Depuis un GUID est toujours 128 bits, vous pouvez omettre le == que vous savez toujours être présent à la fin et cela vous donnera une chaîne de 22 caractères. Ce n'est pas aussi court que YouTube.

65
Dor Cohen

J'utilise une approche similaire à celle de Dor Cohen mais en supprimant certains caractères spéciaux:

var uid = Regex.Replace(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), "[/+=]", "");     

Cela produira uniquement des caractères alphanumériques. Les UID ne sont pas garantis d'avoir toujours la même longueur. Voici un exemple de parcours:

vmKo0zws8k28fR4V4Hgmw 
TKbhS0G2V0KqtpHOU8e6Ug 
rfDi1RdO0aQHTosh9dVvw
3jhCD75fUWjQek8XRmMg 
CQUg1lXIXkWG8KDFy7z6Ow 
bvyxW5aj10OmKA5KMhppw
pIMK8eq5kyvLK67xtsIDg
VX4oljGWpkSQGR2OvGoOQ 
NOHBjUUHv06yIc7EvotRg
iMniAuUG9kiGLwBtBQByfg
22
Jaime

Paquet simple utilisable. Je l'utilise pour le générateur d'identifiant de requête temporel.

https://www.nuget.org/packages/shortid

https://github.com/bolorundurowb/shortid

Utilise System.Random

string id = ShortId.Generate();
// id = KXTR_VzGVUoOY

(de la page github)

Si vous souhaitez contrôler le type d'id généré en spécifiant si vous voulez des nombres, des caractères spéciaux et leur longueur, appelez la méthode Generate et transmettez trois paramètres, le premier un booléen indiquant si vous voulez des nombres, le second un booléen indiquant si vous voulez caractères spéciaux, le dernier un nombre indiquant votre préférence de longueur.

string id = ShortId.Generate(true, false, 12);
// id = VvoCDPazES_w
9
BozoJoe
var ticks = new DateTime(2016,1,1).Ticks;
var ans = DateTime.Now.Ticks - ticks;
var uniqueId = ans.ToString("x");

Conservez une date de référence (dans ce cas, le 1er janvier 2016) à partir de laquelle vous commencerez à générer ces identifiants. Cela rendra vos identifiants plus petits.

8
adeel41

Autant que je sache, le simple fait de retirer une partie d'un GUID n'est pas garanti d'être unique - en fait, c'est loin d'être unique.

La chose la plus courte que je connaisse qui garantisse l’unicité mondiale est décrite dans cet article de blog de Jeff Atwood . Dans l'article lié, il discute de plusieurs façons de raccourcir un GUID et le réduit finalement à 20 octets via Ascii85 encoding .

Cependant, si vous avez absolument besoin d'une solution ne dépassant pas 15 octets, je crains que vous n'ayez d'autre choix que d'utiliser un produit dont la garantie n'est pas unique.

7
Christian Specht

Pour mon application locale, j'utilise cette approche basée sur le temps: 

/// <summary>
/// Returns all ticks, milliseconds or seconds since 1970.
/// 
/// 1 tick = 100 nanoseconds
/// 
/// Samples:
/// 
/// Return unit     value decimal           length      value hex       length
/// --------------------------------------------------------------------------
/// ticks           14094017407993061       17          3212786FA068F0  14
/// milliseconds    1409397614940           13          148271D0BC5     11
/// seconds         1409397492              10          5401D2AE        8
///
/// </summary>
public static string TickIdGet(bool getSecondsNotTicks, bool getMillisecondsNotTicks, bool getHexValue)
{
    string id = string.Empty;

    DateTime historicalDate = new DateTime(1970, 1, 1, 0, 0, 0);

    if (getSecondsNotTicks || getMillisecondsNotTicks)
    {
        TimeSpan spanTillNow = DateTime.UtcNow.Subtract(historicalDate);

        if (getSecondsNotTicks)
            id = String.Format("{0:0}", spanTillNow.TotalSeconds);
        else
            id = String.Format("{0:0}", spanTillNow.TotalMilliseconds);
    }
    else
    {
        long ticksTillNow = DateTime.UtcNow.Ticks - historicalDate.Ticks;
        id = ticksTillNow.ToString();
    }

    if (getHexValue)
        id = long.Parse(id).ToString("X");

    return id;
}
5
Pollitzer

Les valeurs IDENTITY doivent être uniques dans une base de données, mais vous devez être conscient des limites ... par exemple, il est pratiquement impossible d'insérer des données en bloc, ce qui vous ralentira si vous travaillez avec un très grand nombre d'enregistrements.

Vous pourrez également utiliser une valeur de date/heure. J'ai vu plusieurs bases de données où ils utilisent la date/heure pour être le PK, et bien que ce ne soit pas super propre, cela fonctionne. Si vous contrôlez les insertions, vous pouvez effectivement garantir que les valeurs seront uniques dans le code.

4
David

Si votre application ne compte pas quelques MILLIONS de personnes, utilisez-la pour générer une chaîne unique et courte au MÊME MILLISECOND. Vous pouvez envisager d'utiliser la fonction ci-dessous.

private static readonly Object obj = new Object();
private static readonly Random random = new Random();
private string CreateShortUniqueString()
{
    string strDate = DateTime.Now.ToString("yyyyMMddhhmmssfff");
    string randomString ;
    lock (obj)
    {
        randomString = RandomString(3);
    }
    return strDate + randomString; // 16 charater
}
private string RandomString(int length)
{

    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy";
    var random = new Random();
    return new string(Enumerable.Repeat(chars, length)
      .Select(s => s[random.Next(s.Length)]).ToArray());
}

changez aaaa en aa si vous avez juste besoin d'utiliser votre application au cours des 99 prochaines années.
Mise à jour 20160511: Correction de la fonction aléatoire
- Ajouter un objet verrouillé
- Déplacer une variable aléatoire hors de la fonction RandomString
Réf

3
Chinh Phan

ici, ma solution n'est pas sûre pour la concurrence, pas plus de 1000 GUID par secondes et thread-safe.

public static class Extensors
{

    private static object _lockGuidObject;

    public static string GetGuid()
    {

        if (_lockGuidObject == null)
            _lockGuidObject = new object();


        lock (_lockGuidObject)
        {

            Thread.Sleep(1);
            var Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            var epochLong = Convert.ToInt64((DateTime.UtcNow - Epoch).TotalMilliseconds);

            return epochLong.DecimalToArbitrarySystem(36);

        }

    }

    /// <summary>
    /// Converts the given decimal number to the numeral system with the
    /// specified radix (in the range [2, 36]).
    /// </summary>
    /// <param name="decimalNumber">The number to convert.</param>
    /// <param name="radix">The radix of the destination numeral system (in the range [2, 36]).</param>
    /// <returns></returns>
    public static string DecimalToArbitrarySystem(this long decimalNumber, int radix)
    {
        const int BitsInLong = 64;
        const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        if (radix < 2 || radix > Digits.Length)
            throw new ArgumentException("The radix must be >= 2 and <= " + Digits.Length.ToString());

        if (decimalNumber == 0)
            return "0";

        int index = BitsInLong - 1;
        long currentNumber = Math.Abs(decimalNumber);
        char[] charArray = new char[BitsInLong];

        while (currentNumber != 0)
        {
            int remainder = (int)(currentNumber % radix);
            charArray[index--] = Digits[remainder];
            currentNumber = currentNumber / radix;
        }

        string result = new String(charArray, index + 1, BitsInLong - index - 1);
        if (decimalNumber < 0)
        {
            result = "-" + result;
        }

        return result;
    }

code non optimisé, juste échantillon !.

2
ur3an0

Je sais que c'est assez loin de la date postée ... :)

J'ai un générateur qui ne produit que 9 caractères Hexa , par exemple: C9D6F7FF3, C9D6FB52C

public class SlimHexIdGenerator : IIdGenerator
{
    private readonly DateTime _baseDate = new DateTime(2016, 1, 1);
    private readonly IDictionary<long, IList<long>> _cache = new Dictionary<long, IList<long>>();

    public string NewId()
    {
        var now = DateTime.Now.ToString("HHmmssfff");
        var daysDiff = (DateTime.Today - _baseDate).Days;
        var current = long.Parse(string.Format("{0}{1}", daysDiff, now));
        return IdGeneratorHelper.NewId(_cache, current);
    }
}


static class IdGeneratorHelper
{
    public static string NewId(IDictionary<long, IList<long>> cache, long current)
    {
        if (cache.Any() && cache.Keys.Max() < current)
        {
            cache.Clear();
        }

        if (!cache.Any())
        {
            cache.Add(current, new List<long>());
        }

        string secondPart;
        if (cache[current].Any())
        {
            var maxValue = cache[current].Max();
            cache[current].Add(maxValue + 1);
            secondPart = maxValue.ToString(CultureInfo.InvariantCulture);
        }
        else
        {
            cache[current].Add(0);
            secondPart = string.Empty;
        }

        var nextValueFormatted = string.Format("{0}{1}", current, secondPart);
        return UInt64.Parse(nextValueFormatted).ToString("X");
    }
}
1
hazjack

J'utilise ce qui suit pour créer un guide unique (35 caractères).

// Example: 7b08e3d-186b-46f0-99c8-e8252033715d
var strUniqueGuid = Guid.NewGuid().ToString();

Si vous aimez un guide unique de 16 caractères, veuillez utiliser le code ci-dessous.

// Example: 7b08e3d-186b-46f
var strUniqueGuid = Guid.NewGuid().ToString();
strUniqueGuid=strUniqueGuid.Substring(0, 16);
0
Binny

Basé sur la réponse de @ dorcohen et le commentaire de @ pootzko, vous pouvez l'utiliser. C'est sûr sur le fil.

var errorId = System.Web.HttpServerUtility.UrlTokenEncode(Guid.NewGuid().ToByteArray());
0
Ahuman

Si vous n'avez pas besoin de taper la chaîne, vous pouvez utiliser ce qui suit:

static class GuidConverter
{
    public static string GuidToString(Guid g)
    {
        var bytes = g.ToByteArray();
        var sb = new StringBuilder();
        for (var j = 0; j < bytes.Length; j++)
        {
            var c = BitConverter.ToChar(bytes, j);
            sb.Append(c);
            j++;
        }
        return sb.ToString();
    }

    public static Guid StringToGuid(string s) 
        => new Guid(s.SelectMany(BitConverter.GetBytes).ToArray());
}

Cela convertira le Guid en une chaîne de 8 caractères comme ceci:

{b77a49a5-182b-42fa-83a9-824ebd6ab58d} -> "Vous ne trouvez pas ce que vous voulez"

{c5f8f7f5-8a7c-4511-b667-8ad36b446617} -> "Vous ne trouvez pas ce que vous voulez"

0
Whopperle