วิธีสร้างแนวทางกำหนด


103

ในแอปพลิเคชันของเราเรากำลังสร้างไฟล์ Xml ด้วยแอตทริบิวต์ที่มีค่า Guid ค่านี้จำเป็นเพื่อให้สอดคล้องกันระหว่างการอัพเกรดไฟล์ ดังนั้นแม้ว่าทุกอย่างในไฟล์จะเปลี่ยนไป แต่ค่า guid สำหรับแอตทริบิวต์ก็ควรจะยังคงเหมือนเดิม

วิธีแก้ปัญหาที่ชัดเจนวิธีหนึ่งคือการสร้างพจนานุกรมแบบคงที่พร้อมชื่อไฟล์และคำแนะนำที่จะใช้สำหรับพวกเขา จากนั้นเมื่อใดก็ตามที่เราสร้างไฟล์เราจะค้นหาชื่อไฟล์ในพจนานุกรมและใช้คำแนะนำที่เกี่ยวข้อง แต่ไม่สามารถทำได้เนื่องจากเราอาจปรับขนาดเป็น 100 ไฟล์และไม่ต้องการรักษารายการคำแนะนำจำนวนมาก

ดังนั้นอีกวิธีหนึ่งคือทำให้ Guid เหมือนกันตามพา ธ ของไฟล์ เนื่องจากเส้นทางไฟล์และโครงสร้างไดเร็กทอรีแอ็พพลิเคชันของเราไม่ซ้ำกัน Guid จึงควรไม่ซ้ำกันสำหรับพา ธ นั้น ดังนั้นทุกครั้งที่เราทำการอัปเกรดไฟล์จะได้รับคำแนะนำเดียวกันตามเส้นทางของมัน ฉันพบวิธีที่ยอดเยี่ยมวิธีหนึ่งในการสร้าง 'แนวทางกำหนด ' (ขอบคุณ 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 จะเหมือนกันเสมอ

มีแนวทางอื่นหรือวิธีที่แนะนำในการดำเนินการนี้หรือไม่? ข้อดีหรือข้อเสียของวิธีนั้นคืออะไร?

คำตอบ:


151

ตามที่ @bacar กล่าวไว้RFC 4122 §4.3กำหนดวิธีสร้าง UUID ตามชื่อ ข้อดีของการทำเช่นนี้ (โดยใช้แฮช MD5) คือสิ่งเหล่านี้รับประกันว่าจะไม่ชนกับ UUID ที่ไม่ระบุชื่อและมีความเป็นไปได้น้อยมากที่จะชนกับ UUID ตามชื่ออื่น ๆ

NET Framework สำหรับการสร้างสิ่งเหล่านี้ แต่ฉันโพสต์โค้ดบน GitHubที่ใช้อัลกอริทึม สามารถใช้งานได้ดังนี้:

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

เพื่อลดความเสี่ยงในการชนกับ GUID อื่น ๆ ให้มากยิ่งขึ้นคุณสามารถสร้าง GUID ส่วนตัวเพื่อใช้เป็นรหัสเนมสเปซ (แทนที่จะใช้รหัสเนมสเปซ URL ที่กำหนดใน RFC)


5
@Porges: RFC4122 ไม่ถูกต้องและมีข้อผิดพลาดที่แก้ไขรหัส C ( rfc-editor.org/errata_search.php?rfc=4122&eid=1352 ) หากการนำไปใช้งานนี้ไม่สอดคล้องกับ RFC4122 และข้อผิดพลาดโปรดให้รายละเอียดเพิ่มเติม ฉันต้องการที่จะทำให้มันเป็นไปตามมาตรฐาน
Bradley Grainger

1
@BradleyGrainger: ฉันไม่ได้สังเกตว่าขอบคุณ / ขอโทษ! ฉันควรจำไว้เสมอว่าให้ตรวจสอบข้อผิดพลาดเมื่ออ่าน RFC ... :)
porges

3
@ Porges: ยินดีต้อนรับ / ไม่มีปัญหา มันทำให้งงว่าพวกเขาไม่ได้อัปเดต RFC ในสถานที่ด้วยการแก้ไขจาก errata แม้แต่ลิงก์ในตอนท้ายของเอกสารก็จะมีประโยชน์มากกว่าการอาศัยให้ผู้อ่านจดจำเพื่อค้นหา errata (หวังว่าก่อนที่จะเขียนการใช้งานตาม RFC ... )
Bradley Grainger

1
@BradleyGrainger: ถ้าคุณใช้ HTML รุ่นก็มีการเชื่อมโยงไปคหบดีจากส่วนหัวเช่นtools.ietf.org/html/rfc4122 ฉันสงสัยว่ามีส่วนขยายเบราว์เซอร์ที่จะเปลี่ยนเส้นทางไปยังเวอร์ชัน HTML เสมอหรือไม่
porges

2
คุณควรพิจารณาบริจาคสิ่งนี้ให้กับ. NET .NET repo อยู่ที่นี่: github.com/dotnet/coreclr/tree/master/src/mscorlib/src/System
sapphiremirage

29

สิ่งนี้จะแปลงสตริงใด ๆ เป็น 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 อย่างสม่ำเสมอ


พบว่าข้อมูลโค้ดนี้มีประโยชน์เมื่อใช้ตัวระบุเฉพาะในฐานข้อมูลสำหรับการแจกจ่ายแบบรวมศูนย์
Gleno

6
คำเตือน! รหัสนี้ไม่ได้สร้าง Guids / UUID ที่ถูกต้อง (ตามที่ bacar ระบุไว้ด้านล่าง) ไม่ได้ตั้งค่าฟิลด์เวอร์ชันหรือประเภทอย่างถูกต้อง
MarkusSchaber

3
การใช้ MD5CryptoServiceProvider แทน SHA1 จะมีประสิทธิภาพเท่ากันหรือไม่เนื่องจาก MD5 มีความยาว 16 ไบต์อยู่แล้ว
Brain2000

20

ตามที่ Rob กล่าวถึงวิธีการของคุณไม่ได้สร้าง UUID แต่จะสร้างแฮชที่ดูเหมือน UUID

RFC 4122ใน UUIDs โดยเฉพาะช่วยให้การกำหนด (ชื่อ-based) UUIDs - รุ่น 3 และ 5 ใช้ MD5 และ SHA1 (ตามลำดับ) คนส่วนใหญ่น่าจะคุ้นเคยกับเวอร์ชัน 4 ซึ่งเป็นแบบสุ่ม Wikipediaให้ภาพรวมที่ดีของเวอร์ชันต่างๆ (โปรดทราบว่าการใช้คำว่า 'เวอร์ชัน' ที่นี่ดูเหมือนจะอธิบายถึง 'ประเภท' ของ UUID - เวอร์ชัน 5 ไม่ได้ใช้แทนเวอร์ชัน 4)

ดูเหมือนจะเป็นห้องสมุดกี่ออกมีสำหรับรุ่นสร้าง 3/5 UUIDs รวมทั้งงูหลามโมดูล uuid , boost.uuid (C ++) และOSSP UUID (ฉันไม่ได้มองหา. net ใด ๆ )


1
นี่คือสิ่งที่ตามหลังโปสเตอร์ต้นฉบับ UUID มีอัลกอริทึมอยู่แล้วเพื่อให้คุณเริ่มต้นด้วยสตริงและแปลงเป็น GUID UUID เวอร์ชัน 3 แฮชสตริงด้วย MD5 ในขณะที่เวอร์ชัน 5 แฮชด้วย SHA1 จุดสำคัญในการสร้าง "guid" คือการทำให้ "ไม่ซ้ำ" เทียบกับ GUID อื่น ๆ อัลกอริทึมกำหนดสองบิตที่ต้องตั้งค่าเช่นเดียวกับการแทะถูกตั้งค่าเป็น 3 หรือ 5 ขึ้นอยู่กับว่าเป็นเวอร์ชัน 3 หรือ 5
Ian Boyd

2
เกี่ยวกับการใช้คำว่า "เวอร์ชัน" RFC 4122 §4.1.3ระบุว่า "เวอร์ชันนี้เป็นประเภทย่อยที่ถูกต้องมากขึ้นอีกครั้งเรายังคงรักษาข้อกำหนดสำหรับความเข้ากันได้"
Bradley Grainger

11
ฉันโพสต์รหัส C # เพื่อสร้าง v3 และ v5 GUID บน GitHub: github.com/LogosBible/Logos.Utility/blob/master/src/…
Bradley Grainger

@BradleyGrainger ฉันได้รับคำเตือน Bitwise หรือตัวดำเนินการที่ใช้กับตัวถูกดำเนินการขยายสัญญาณ พิจารณาคัดเลือกนักแสดงเป็นประเภทที่ไม่ได้ลงนามขนาดเล็กก่อน
เซบาสเตียน

1
นี่กำลังจะนอกประเด็น! แนะนำให้ย้ายรายงานข้อผิดพลาด lib แต่ละรายการไปยัง GitHub
บาคาร์

3

คุณต้องสร้างความแตกต่างระหว่างอินสแตนซ์ของคลาสGuidและตัวระบุที่ไม่ซ้ำกันทั่วโลก "แนวทางกำหนดปัจจัย" คือแฮช (ตามหลักฐานจากการเรียกร้องของคุณprovider.ComputeHash) แฮชมีโอกาสที่จะเกิดการชนกันสูงกว่ามาก (สองสตริงที่แตกต่างกันเกิดขึ้นเพื่อสร้างแฮชเดียวกัน) มากกว่าที่ Guid สร้างผ่านGuid.NewGuid.

ดังนั้นปัญหาในแนวทางของคุณคือคุณจะต้องตกลงกับความเป็นไปได้ที่สองเส้นทางที่แตกต่างกันจะสร้าง GUID เดียวกัน หากคุณจำเป็นต้องระบุที่ไม่ซ้ำกันสำหรับสตริงเส้นทางใดก็ตามแล้วสิ่งที่ง่ายที่สุดที่จะทำคือเพียงแค่ใช้สตริง หากคุณต้องการให้สตริงถูกบดบังจากผู้ใช้ของคุณให้เข้ารหัส - คุณสามารถใช้ ROT13 หรือสิ่งที่มีประสิทธิภาพมากกว่า ...

การพยายามใส่รองเท้าที่ไม่ใช่ GUID บริสุทธิ์ลงในประเภทข้อมูล GUID อาจทำให้เกิดปัญหาการบำรุงรักษาในอนาคต ...


2
คุณอ้างว่า "แฮชมีโอกาสชนกันสูงกว่ามาก ... กว่าที่ Guid สร้างผ่าน Guid.NewGuid" คุณสามารถอธิบายได้หรือไม่? จากมุมมองทางคณิตศาสตร์จำนวนบิตที่สามารถกำหนดได้จะเหมือนกันและทั้ง MD5 และ SHA1 เป็นแฮชที่เข้ารหัสซึ่งออกแบบมาโดยเฉพาะเพื่อลดความน่าจะเป็นของการชนแฮช (โดยบังเอิญและโดยเจตนา)
MarkusSchaber

ฉันจะบอกว่าความแตกต่างที่สำคัญคือการเข้ารหัสแฮชแมปจากช่องว่างที่ไม่มีที่สิ้นสุดหนึ่งไปยังอีกพื้นที่คงที่โดยใช้ฟังก์ชัน การสร้างภาพแฮชที่แมปสตริงความยาวตัวแปรเป็น 128 บิตในขณะที่ Guid สร้าง 128 บิตแบบสุ่มหลอก การสร้างแบบสุ่มหลอกไม่ได้อาศัยอินพุตเริ่มต้น แต่เป็นการสร้างเอาต์พุตอย่างสม่ำเสมอในพื้นที่เอาต์พุตโดยใช้การสุ่มจากฮาร์ดแวร์หรือวิธีการอื่น
Thai Bui

2

MD5 อ่อนแอฉันเชื่อว่าคุณสามารถทำสิ่งเดียวกันกับ SHA-1 และได้ผลลัพธ์ที่ดีกว่า

BTW เป็นเพียงความเห็นส่วนตัวการแต่งแฮช md5 เป็น GUID ไม่ได้ทำให้เป็น GUID ที่ดี GUID โดยธรรมชาติแล้วไม่ได้กำหนด รู้สึกเหมือนเป็นการโกง ทำไมไม่เรียกจอบจอบแล้วพูดว่ามันเป็นสตริงที่แสดงผลแฮชของอินพุต คุณสามารถทำได้โดยใช้บรรทัดนี้แทนที่จะเป็น guid line ใหม่:

string stringHash = BitConverter.ToString(hashBytes)

ขอบคุณสำหรับข้อมูลของคุณ แต่สิ่งนี้ยังให้สตริงฉันและฉันกำลังมองหา GUID ...
Punit Vora

ตกลงเรียกแฮชของคุณว่า "GUID" แก้ไขปัญหาได้แล้ว หรือเป็นปัญหาจริงที่คุณต้องGuidวัตถุ?
user7116

ฉันหวังว่ามันจะง่ายขนาดนั้น .. :) แต่ใช่ฉันต้องการวัตถุ 'GUID'
Punit Vora

5
"GUID ตามธรรมชาติของพวกมันไม่ได้เป็นตัวกำหนด" - นี่เป็นความจริงสำหรับ GUID บางประเภท ('เวอร์ชัน') เท่านั้น อย่างไรก็ตามฉันยอมรับว่า "การแต่งแฮช md5 เป็น GUID ไม่ได้ทำให้เป็น GUID ที่ดี" ด้วยเหตุผลอื่น ๆ ตามที่ @Bradley Grainger และ @Rob Fonseca-Ensor สะกดและคำตอบของฉันสำหรับคำถามนี้
bacar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.