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?
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.
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
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
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.
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.
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;
}
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.
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
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 !.
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");
}
}
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);
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());
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"