ฉันต้องการรวบรวมข้อมูลให้มากที่สุดเท่าที่จะเป็นไปได้เกี่ยวกับการกำหนดเวอร์ชัน API ใน. NET / CLR และโดยเฉพาะการเปลี่ยนแปลง API ที่ทำหรือไม่ทำลายแอปพลิเคชันไคลเอนต์ ก่อนอื่นมานิยามคำศัพท์กัน:
การเปลี่ยนแปลง API - การเปลี่ยนแปลงคำจำกัดความที่มองเห็นแบบสาธารณะรวมถึงสมาชิกสาธารณะใด ๆ ซึ่งรวมถึงการเปลี่ยนประเภทและชื่อสมาชิกการเปลี่ยนประเภทพื้นฐานการเพิ่ม / การลบอินเตอร์เฟสจากรายการอินเตอร์เฟสที่ใช้งานการเพิ่ม / ลบสมาชิก (รวมถึงการโอเวอร์โหลด) การเปลี่ยนการมองเห็นสมาชิกวิธีการเปลี่ยนชื่อและพารามิเตอร์ชนิดการเพิ่มค่าเริ่มต้น สำหรับพารามิเตอร์เมธอดการเพิ่ม / ลบแอ็ตทริบิวต์กับชนิดและสมาชิกและการเพิ่ม / ลบพารามิเตอร์ประเภททั่วไปบนประเภทและสมาชิก (ฉันพลาดอะไรเลยหรือ?) สิ่งนี้ไม่รวมถึงการเปลี่ยนแปลงใด ๆ ในเนื้อความของสมาชิกหรือการเปลี่ยนแปลงใด ๆ กับสมาชิกส่วนตัว (เช่นเราไม่คำนึงถึงการสะท้อนกลับ)
ตัวแบ่งระดับไบนารี - การเปลี่ยนแปลง API ที่ส่งผลให้แอสเซมบลีไคลเอนต์ที่คอมไพล์เทียบกับเวอร์ชันเก่ากว่าของ API อาจไม่โหลดด้วยเวอร์ชันใหม่ ตัวอย่าง: การเปลี่ยนลายเซ็นเมธอดแม้ว่าจะอนุญาตให้เรียกในลักษณะเดียวกับก่อนหน้า (เช่น: void เพื่อส่งคืนค่าเริ่มต้นของประเภท / พารามิเตอร์เกินพิกัด)
ตัวแบ่งระดับซอร์ส - การเปลี่ยนแปลง API ที่ส่งผลให้โค้ดที่มีอยู่ถูกเขียนเพื่อคอมไพล์เทียบกับเวอร์ชันเก่ากว่าของ API ที่อาจไม่คอมไพล์ด้วยเวอร์ชันใหม่ แอสเซมบลีไคลเอนต์ที่คอมไพล์แล้วทำงานเหมือน แต่ก่อน ตัวอย่าง: การเพิ่มโอเวอร์โหลดใหม่ที่อาจทำให้เกิดความกำกวมในการเรียกใช้เมธอดที่ไม่ชัดเจนก่อนหน้านี้
การเปลี่ยนแปลงซีแมนทิกส์ระดับซอร์สนั้นเป็นการเปลี่ยนแปลง API ซึ่งส่งผลให้โค้ดที่มีอยู่เขียนขึ้นเพื่อคอมไพล์กับเวอร์ชันเก่าของ API เปลี่ยนซีแมนทิกส์อย่างเงียบ ๆ เช่นโดยเรียกวิธีการอื่น รหัสควรรวบรวมต่อไปโดยไม่มีคำเตือน / ข้อผิดพลาดและแอสเซมบลีที่รวบรวมไว้ก่อนหน้านี้ควรทำงานเหมือนก่อน ตัวอย่าง: การใช้อินเทอร์เฟซใหม่บนคลาสที่มีอยู่ซึ่งส่งผลให้มีการเลือกเกินพิกัดที่แตกต่างกันระหว่างการแก้ปัญหาโอเวอร์โหลด
เป้าหมายสูงสุดคือการจัดหมวดหมู่การเปลี่ยนแปลง API ของซีแมนทิกส์ที่เงียบและสงบที่สุดให้มากที่สุดเท่าที่จะทำได้และอธิบายถึงผลกระทบที่แท้จริงของการแตกหักและภาษาใดบ้างที่ไม่ได้รับผลกระทบ ในการขยายในภายหลัง: ในขณะที่การเปลี่ยนแปลงบางอย่างส่งผลกระทบต่อทุกภาษาในระดับสากล (เช่นการเพิ่มสมาชิกใหม่ไปยังอินเทอร์เฟซจะทำลายการใช้งานของอินเทอร์เฟซนั้นในภาษาใด ๆ ) บางคนต้องการความหมายภาษาเฉพาะอย่างมาก โดยทั่วไปมักเกี่ยวข้องกับวิธีการมากไปและโดยทั่วไปแล้วสิ่งที่เกี่ยวข้องกับการแปลงประเภทโดยนัย ดูเหมือนจะไม่มีทางใดที่จะกำหนด "ตัวหารร่วมที่น้อยที่สุด" ที่นี่แม้สำหรับภาษาที่สอดคล้องกับ CLS (นั่นคือภาษาที่สอดคล้องกับกฎของ "ผู้บริโภค CLS" อย่างน้อยตามที่กำหนดไว้ในข้อกำหนด CLI) - แม้ว่าฉันจะ จะขอบคุณถ้ามีคนแก้ไขฉันว่าทำผิดที่นี่ - นี่จะต้องใช้ภาษาเป็นภาษา สิ่งที่น่าสนใจที่สุดคือสิ่งที่มาพร้อมกับ. NET แบบนอกกรอบ: C #, VB และ F #; แต่คนอื่น ๆ เช่น IronPython, IronRuby, Delphi Prism เป็นต้นก็มีความเกี่ยวข้องเช่นกัน ยิ่งมีมุมมากเท่าไหร่ก็ยิ่งมีความน่าสนใจมากขึ้นเท่านั้น - สิ่งต่าง ๆ เช่นการลบสมาชิกนั้นค่อนข้างชัดเจนในตัวเอง แต่การโต้ตอบที่ลึกซึ้งระหว่างวิธีการโอเวอร์โหลดวิธีการพารามิเตอร์ทางเลือก / ค่าเริ่มต้นการอนุมานประเภทแลมบ์ดา ในช่วงเวลาที่.
ตัวอย่างเล็ก ๆ น้อย ๆ ที่จะเริ่มต้นนี้:
การเพิ่มเมธอด overloads ใหม่
ชนิด: ตัวแบ่งระดับซอร์ส
ภาษาที่ได้รับผลกระทบ: C #, VB, F #
API ก่อนการเปลี่ยนแปลง:
public class Foo
{
public void Bar(IEnumerable x);
}
API หลังการเปลี่ยนแปลง:
public class Foo
{
public void Bar(IEnumerable x);
public void Bar(ICloneable x);
}
ตัวอย่างรหัสลูกค้าที่ทำงานก่อนที่จะเปลี่ยนและแตกหลังจาก:
new Foo().Bar(new int[0]);
การเพิ่มตัวดำเนินการแปลงใหม่ให้เกินพิกัด
ชนิด: ตัวแบ่งระดับซอร์ส
ภาษาที่ได้รับผลกระทบ: C #, VB
ภาษาที่ไม่ได้รับผลกระทบ: F #
API ก่อนการเปลี่ยนแปลง:
public class Foo
{
public static implicit operator int ();
}
API หลังการเปลี่ยนแปลง:
public class Foo
{
public static implicit operator int ();
public static implicit operator float ();
}
ตัวอย่างรหัสลูกค้าที่ทำงานก่อนที่จะเปลี่ยนและแตกหลังจาก:
void Bar(int x);
void Bar(float x);
Bar(new Foo());
หมายเหตุ: F # ไม่แตกสลายเนื่องจากไม่มีการสนับสนุนระดับภาษาใด ๆ สำหรับโอเปอเรเตอร์ที่โอเวอร์โหลดไม่ชัดเจนหรือโดยนัย - ทั้งคู่จะต้องถูกเรียกโดยตรงop_Explicit
และop_Implicit
วิธีการ
การเพิ่มวิธีการใหม่เช่น
ชนิด: ความหมายที่เงียบสงบระดับแหล่งข้อมูลเปลี่ยนแปลง
ภาษาที่ได้รับผลกระทบ: C #, VB
ภาษาที่ไม่ได้รับผลกระทบ: F #
API ก่อนการเปลี่ยนแปลง:
public class Foo
{
}
API หลังการเปลี่ยนแปลง:
public class Foo
{
public void Bar();
}
ตัวอย่างรหัสลูกค้าที่มีความหมายเงียบ ๆ เปลี่ยนไป:
public static class FooExtensions
{
public void Bar(this Foo foo);
}
new Foo().Bar();
หมายเหตุ: F # ไม่เสียหายเนื่องจากไม่มีการสนับสนุนระดับภาษาExtensionMethodAttribute
และต้องการวิธีการขยาย CLS ที่จะเรียกว่าเป็นวิธีการคงที่