118

このアプリケーションでは、Guid値を持つ属性を持つXmlファイルを作成しています。この値は、ファイルのアップグレード間で一貫している必要がありました。したがって、ファイル内の他のすべてが変更された場合でも、属性のGUID値は同じままである必要があります。

明らかな解決策の1つは、ファイル名とそれに使用するGUIDを使用して静的辞書を作成することでした。次に、ファイルを生成するたびに、辞書でファイル名を検索し、対応するGUIDを使用します。しかし、これは実行可能ではありません。何百ものファイルに拡張でき、GUIDの大きなリストを維持したくないためです。

したがって、別のアプローチは、ファイルのパスに基づいてGUIDを同じにすることでした。ファイルパスとアプリケーションディレクトリ構造は一意であるため、Guidはそのパスに対して一意である必要があります。したがって、アップグレードを実行するたびに、ファイルはそのパスに基づいて同じGUIDを取得します。そのような「決定論的ガイド」を生成するための1つのクールな方法を見つけました(Elton Stonemanに感謝します)。それは基本的にこれを行います:

private Guid GetDeterministicGuid(string input) 

{ 

//use MD5 hash to get a 16-byte hash of the string: 

MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider(); 

byte[] inputBytes = Encoding.Default.GetBytes(input); 

byte[] hashBytes = provider.ComputeHash(inputBytes); 

//generate a guid from the hash: 

Guid hashGuid = new Guid(hashBytes); 

return hashGuid; 

} 

したがって、文字列が与えられると、GUIDは常に同じになります。

これを行うための他のアプローチまたは推奨される方法はありますか?その方法の長所と短所は何ですか?

4

6 に答える 6

164

@bacar が述べたように、RFC 4122 §4.3 は、名前ベースの UUID を作成する方法を定義しています。(MD5 ハッシュを使用するよりも) これを行う利点は、これらが名前ベースでない UUID と衝突しないことが保証されており、他の名前ベースの UUID と衝突する可能性が非常に (非常に) 小さいことです。

これらを作成するための .NET Framework のネイティブ サポートはありませんが、アルゴリズムを実装するコードを GitHubに投稿しました。次のように使用できます。

Guid guid = GuidUtility.Create(GuidUtility.UrlNamespace, filePath);

他の GUID との衝突のリスクをさらに減らすために、(RFC で定義された URL 名前空間 ID を使用する代わりに) 名前空間 ID として使用するプライベート GUID を作成できます。

于 2011-04-14T01:15:30.180 に答える
30

これにより、外部アセンブリをインポートすることなく、任意の文字列が Guid に変換されます。

public static Guid ToGuid(string src)
{
    byte[] stringbytes = Encoding.UTF8.GetBytes(src);
    byte[] hashedBytes = new System.Security.Cryptography
        .SHA1CryptoServiceProvider()
        .ComputeHash(stringbytes);
    Array.Resize(ref hashedBytes, 16);
    return new Guid(hashedBytes);
}

一意の Guid を生成するためのより良い方法は他にもありますが、これは一貫して文字列データ キーを Guid データ キーにアップグレードする方法です。

于 2012-02-21T22:14:38.863 に答える
22

Rob が言及しているように、あなたのメソッドは UUID を生成しません。UUID のようなハッシュを生成します。

UUIDに関するRFC 4122では、特に決定論的な (名前ベースの) UUID が許可されています。バージョン 3 と 5 では、md5 と SHA1 が使用されます (それぞれ)。ほとんどの人はおそらく、ランダムなバージョン 4 に精通しています。ウィキペディアは、バージョンの概要を説明しています。(ここでの「バージョン」という言葉の使用は、UUID の「タイプ」を表しているように見えることに注意してください。バージョン 5 はバージョン 4 に取って代わるものではありません)。

python uuid モジュールboost.uuid (C++)、OSSP UUIDなど、バージョン 3/5 UUID を生成するためのライブラリがいくつかあるようです。(.netのものは探していません)

于 2010-06-11T14:09:18.817 に答える
3

Guidclass のインスタンスと、グローバルに一意な識別子を区別する必要があります。「決定論的GUID」は実際にはハッシュです(への呼び出しによって証明されるようにprovider.ComputeHash)。ハッシュは、Guid.NewGuid.

したがって、あなたのアプローチの問題は、2 つの異なるパスが同じ GUID を生成する可能性に問題がないことです。特定のパス文字列に対して一意の識別子が必要な場合、最も簡単なのは string を使用することです。ユーザーから文字列を隠す必要がある場合は、暗号化します-ROT13またはより強力なものを使用できます...

純粋な GUID ではないものを GUID データ型に押し込もうとすると、将来的にメンテナンスの問題が発生する可能性があります...

于 2010-04-19T15:35:02.733 に答える
1

MD5 は弱いです。SHA-1 で同じことを行うと、より良い結果が得られると思います。

ところで、単なる個人的な意見ですが、md5 ハッシュを GUID としてドレスアップしても、それは適切な GUID にはなりません。GUID は、その性質上、非決定的です。これはチートのように感じます。スペードをスペードと呼んで、入力のハッシュをレンダリングした文字列とだけ言ってみませんか。新しい guid 行ではなく、次の行を使用してそれを行うことができます。

string stringHash = BitConverter.ToString(hashBytes)
于 2010-04-15T02:28:20.240 に答える
0

ユニット/統合テストなどには十分なはずの非常に単純なソリューションを次に示します。

var rnd = new Random(1234); // Seeded random number (deterministic).
Console.WriteLine($"{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}-{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}-{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}-{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}-{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}{rnd.Next(0, 255):x2}");
于 2021-07-27T12:45:00.433 に答える