คุณสมบัติ“ รุ่นเฉพาะ” ของการอ้างอิงแอสเซมบลีทำงานอย่างไรใน Visual Studio


156

วันนี้ฉันได้ดูคุณสมบัติ "รุ่นเฉพาะ" ของการอ้างอิงแอสเซมบลีใน Visual Studio 2010 อย่างใกล้ชิดหลังจากการทดลองสองสามครั้งโดยมีผลลัพธ์ที่ไม่คาดคิด ถึงกระนั้นฉันก็ดูเหมือนจะไม่มีคำตอบทั้งหมดดังนั้นนี่คือความพยายามของฉันในการตอบคำถามด้วยตนเอง:

วิธีว่าไม่ "โดยเฉพาะรุ่น" ทรัพย์สินของงานที่อ้างอิงประกอบใน Visual Studio?

คำตอบ:


255

มันเป็นทรัพย์สินที่รวบรวมเวลา!

หนึ่งในสิ่งที่สำคัญที่สุดที่ควรทราบคือ "รุ่นเฉพาะ" เป็นคุณสมบัติที่มีผลบังคับใช้ในเวลารวบรวมและไม่ใช่เวลาใช้งานจริง

มันเกี่ยวกับอะไร?

เมื่อโครงการถูกสร้างขึ้นการอ้างอิงแอสเซมบลีของโครงการจะต้องได้รับการแก้ไขเพื่อหาส่วนประกอบทางกายภาพที่ระบบการสร้างควรใช้ หากการตรวจสอบ "รุ่นที่ระบุ" ดำเนินการ (ดูหัวข้อ "เมื่อใดที่" การตรวจสอบ "รุ่นที่เฉพาะเจาะจง") จะมีผลต่อผลลัพธ์ของกระบวนการแก้ปัญหาการชุมนุม:

  • ระบบบิลด์จะหาตำแหน่งชุดฟิสิคัลที่สามารถใช้งานได้
  • ระบบบิลด์จะเปรียบเทียบเวอร์ชันของชุดประกอบแบบฟิสิคัลกับรุ่นชุดประกอบที่เก็บไว้ในไฟล์. csproj สำหรับการอ้างอิงชุดประกอบ
  • หากทั้งสองเวอร์ชันแอสเซมบลีเหมือนกันทุกอย่างกระบวนการแก้ไขปัญหาสำเร็จและฟิสิคัลแอสเซมบลีที่พบจะใช้สำหรับการสร้าง
  • หากทั้งสองเวอร์ชันแอสเซมบลีไม่ตรงกันแอสเซมบลีทางกายภาพจะถูกละทิ้งและกระบวนการแก้ปัญหาดำเนินต่อไปโดยการค้นหาแอสเซมบลีที่อาจเกิดขึ้นถัดไป
  • ถ้าไม่สามารถหาตำแหน่งฟิสิคัลที่เป็นไปได้อีกต่อไปกระบวนการแก้ไขปัญหาจะล้มเหลว ซึ่งส่งผลให้คำเตือนคอมไพเลอร์ (เตือน MSB3245) ที่บอกคุณว่าการอ้างอิงไม่สามารถแก้ไขได้
  • ที่น่าสนใจคือการสร้างนั้นยังคงดำเนินต่อไป! ถ้ารหัสไม่มีการอ้างอิงจริงไปยังแอสเซมบลีบิลด์สำเร็จ (พร้อมคำเตือนที่กล่าวถึงก่อนหน้านี้) ถ้ารหัสมีการอ้างอิงบิลด์ล้มเหลวโดยมีข้อผิดพลาดที่ดูราวกับว่าโค้ดกำลังใช้ชนิดหรือเนมสเปซที่ไม่รู้จัก สิ่งบ่งชี้เพียงอย่างเดียวว่าทำไมบิลด์ที่ล้มเหลวจริงๆก็คือคำเตือน MSB3245

ลำดับที่แอสเซมบลีได้รับการแก้ไข

ลำดับที่กระบวนการแก้ไขปัญหาแอสเซมบลีหาตำแหน่งที่ตั้งแอสเซมบลีที่อาจเกิดขึ้นปรากฏเป็น:

  1. แอสเซมบลีที่อ้างอิงโดย<HintPath>องค์ประกอบในไฟล์. csproj
  2. เส้นทางผลลัพธ์ของโครงการ
  3. The GAC

โปรดทราบว่าหากมีแอสเซมบลีหลายรุ่นอยู่ใน GAC กระบวนการแก้ปัญหาจะพยายามแก้ไขแอสเซมบลีเป็นเวอร์ชันสูงสุดก่อน นี่เป็นสิ่งสำคัญเฉพาะในกรณีที่ไม่ได้ทำการตรวจสอบ

เมื่อมีการตรวจสอบ "เฉพาะรุ่น"

Visual Studio พิจารณาการตัดสินใจว่าจะทำการตรวจสอบ "เวอร์ชันเฉพาะ" บนข้อมูลสองชิ้นที่พบในไฟล์. csproj หรือไม่:

  • การมีหรือไม่มี<SpecificVersion>องค์ประกอบและค่าของมัน (ถ้ามี)
  • มีหรือไม่มีข้อมูลเวอร์ชันในการอ้างอิงชุดประกอบ

นี่เป็นลักษณะการอ้างอิงแอสเซมบลีทั่วไปที่มีข้อมูลเวอร์ชันเป็นอย่างไร:

<Reference Include="Foo, Version=1.2.3.4, Culture=neutral, processorArchitecture=MSIL">
  <SpecificVersion>True</SpecificVersion>
  <HintPath>..\..\Bar\Foo.dll</HintPath>
</Reference>

และนี่คือลักษณะการอ้างอิงแอสเซมบลีที่ดูเหมือนไม่มีข้อมูลรุ่น:

<Reference Include="Foo">
[...]

ตารางต่อไปนี้จะแสดงเมื่อมีการตรวจสอบ "รุ่นที่ระบุ" และเมื่อไม่มี

                            |     Version information
                            |  Present       Not present
----------------------------+------------------------------
<SpecificVersion>           |
- Present, has value True   |    Yes (1)        Yes (check always fails) (2)
- Present, has value False  |    No  (3)        No (4)
- Not present               |    Yes (5)        No (6)

สิ่งที่น่าแปลกใจที่นี่คือไม่มีการตรวจสอบหากทั้งสองอย่าง<SpecificVersion>และข้อมูลเวอร์ชั่นขาดหายไป (กรณีที่ 6) ฉันคาดว่าจะมีการตรวจสอบและจะล้มเหลวเสมอ (เช่นเดียวกับกรณีที่ 2) เนื่องจากในความเข้าใจของฉันการไม่มีการ<SpecificVersion>บอกเป็นนัยถึงค่าเริ่มต้น "True" นี่อาจเป็นเรื่องแปลกสำหรับ Visual Studio 2010 ที่ฉันทำการทดสอบ

เมื่อคุณตรวจสอบคุณสมบัติของการอ้างอิงแอสเซมบลีใน Visual Studio UI (เลือกการอ้างอิงและกด F4), ค่าที่คุณเห็นสำหรับคุณสมบัติ "รุ่นที่เฉพาะเจาะจง" จะบอกคุณว่า Visual Studio กำลังจะทำการ "เวอร์ชั่นเฉพาะ" หรือไม่ ตรวจสอบ ในกรณีที่ 6 UI จะแสดง "True" แม้ว่า<SpecificVersion>องค์ประกอบจะไม่ปรากฏในไฟล์. csproj

ผลข้างเคียงที่ "Copy local"

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

วัสดุอ้างอิง


ขอบคุณสำหรับรายละเอียด ฉันสามารถตรวจสอบได้ ... การตรวจสอบเวอร์ชั่นชุดประกอบจะเกิดขึ้นสำหรับชุดประกอบที่มีชื่อเรียกเท่านั้น นั่นถูกต้องใช่ไหม? นอกจากนี้เมื่อเราพูดถึงการตรวจสอบเวอร์ชั่นของชุดประกอบ - ทำโดยเปรียบเทียบชื่อชุดประกอบที่อ้างอิงหรือไม่ (ในกรณีที่มีความแข็งแกร่งที่มีชื่อการชุมนุมว่าชื่อรวมถึงข้อมูลเกี่ยวกับรุ่นจึงไม่เหมือนสนามรุ่นแยกต่างหากมีการตรวจสอบ?)
กาวินหวัง

2
@GavinHope คำถามที่ 1: ไม่การตรวจสอบเวอร์ชั่นไม่ จำกัด เฉพาะชื่อที่แข็งแกร่งส่วนใหญ่เป็นเพราะชื่อแอสเซมบลีสามารถรวมเวอร์ชันได้ แต่ก็ยังไม่ได้เป็นชื่อที่แข็งแกร่ง (เช่นถ้าไม่มีPublicKeyToken=ส่วน) นอกจากนี้หากคุณตรวจสอบตารางในตอนท้ายของโพสต์ของฉันคุณจะเห็นว่าการตรวจสอบเวอร์ชันสามารถเกิดขึ้นได้แม้ว่าชิ้นVersion=ส่วนจะหายไปจากชื่อชุดประกอบใน. csproj คำถามที่ 2: ฉันคิดว่าชื่อแอสเซมบลีใช้สำหรับการเปรียบเทียบใช่ ฉันไม่รู้แหล่งอื่นใดสำหรับข้อมูล
herzbube

"ในกรณีที่ 6 UI จะแสดง" True "แม้ว่าองค์ประกอบ <SpecificVersion> จะไม่ปรากฏในไฟล์. csproj" - ปรากฏว่าค่าเริ่มต้นเป็นทรู หลังจากสลับเฉพาะรุ่นใน UI ที่จะทรู<SpecificVersion>แท็กที่ละอย่างสมบูรณ์ซึ่งก่อนหน้านี้มีค่าเป็นเท็จ
samis

@herzbube - ฉันคิดว่าความหมายของ "เวอร์ชั่นเฉพาะ" ในหน้าต่าง Visual Studio> คุณสมบัติของโครงการตรงข้ามกับสิ่งที่คุณพูดที่นี่ (ซึ่งตรงกันข้ามกับสิ่งที่คุณคาดหวัง) Visual Studio กล่าวว่าค่า (จริงหรือเท็จ) ของ "รุ่นที่ระบุ" "ระบุว่าแอสเซมบลีนี้สามารถแก้ไขได้โดยไม่คำนึงถึงกฎการกำหนดเป้าหมายหลายเป้าหมายสำหรับการแก้ไขแอสเซมบลี"
N73k

35

เมื่อคุณเพิ่มการอ้างอิงแล้ว Visual Studio จะบันทึก [AssemblyVersion] ของแอสเซมบลีในไฟล์โครงการ นี้เป็นสิ่งสำคัญ. ถ้าคุณบอกว่าสร้างการแก้ไขข้อบกพร่องในอีกหนึ่งปีต่อมาจากนั้นคุณต้องการตรวจสอบให้แน่ใจว่าคุณได้สร้างโครงการใหม่ด้วยการอ้างอิงเวอร์ชันเดียวกันที่แน่นอนดังนั้นจึงเป็นการดรอปอินที่แท้จริง คุณจะได้รับข้อผิดพลาดหากมีการเปลี่ยนแปลงการชุมนุมอ้างอิง

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

ค่อนข้างสำคัญที่ต้องเข้าใจผลที่ตามมาคุณจำเป็นต้องปรับใช้โครงสร้างทั้งหมดของโปรแกรมใหม่เพื่อหลีกเลี่ยงอุบัติเหตุ เวอร์ชันไม่ตรงกันที่รันไทม์ขัดข้องของโปรแกรมและสามารถถูกระงับด้วย<bindingRedirect>ไฟล์. config ที่มีความเสี่ยงเท่านั้น


2
ขอขอบคุณสำหรับข้อมูลว่าทำไม "รุ่นเฉพาะ" จึงเป็นสิ่งสำคัญนี่เป็นคู่หูที่ดีในแง่มุมเชิงกลอย่างแท้จริงที่ฉันครอบคลุมในคำตอบของฉัน
herzbube

@Hans Passant - ย่อหน้าสุดท้ายของคุณใช้ได้กับ SpecificVersion จริงหรือเท็จ? ฉันคิดว่าสิ่งเหล่านี้เป็นผลที่ตามมาเมื่อคุณตั้งค่าเป็นจริง
GreenEyedAndy

1
รุ่นเฉพาะใช้กับการสร้างแอปของคุณเท่านั้น ที่รันไทม์ CLR จะยืนยันในการจับคู่ที่ตรงกันเสมอพร้อมกับหมายเลขรุ่นชุดประกอบการอ้างอิง หากคุณใช้เวอร์ชันที่ใหม่กว่า ณ เวลาบิลด์มันต้องเป็นเวอร์ชันที่ใหม่กว่า ณ รันไทม์เช่นกัน
Hans Passant

1
ระวัง VS2013 & .Net 4.5.1 AutoGenerateBindingRedirectsพวกเขาอาจเปลี่ยนเส้นทางการเชื่อมโยง dll ไปเป็นเวอร์ชั่นที่ใหม่กว่าแม้ว่าคุณจะบอกให้ใช้รุ่นที่เฉพาะเจาะจง
Dennis Kuypers

1
@HansPassant ฉันคิดว่า CLR ไม่ได้คำนึงถึง[AssemblyVersion]เมื่อการชุมนุมไม่ได้ลงนามในชื่อที่แข็งแกร่ง
tm1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.