ก่อนอื่นขอบอกว่าคำตอบของจอนนั้นถูกต้อง นี่เป็นหนึ่งในส่วนที่มีขนดกที่สุดของข้อมูลจำเพาะดังนั้นจอนจึงควรดำน้ำลงไปก่อน
อย่างที่สองขอบอกว่าบรรทัดนี้:
การแปลงโดยนัยมีอยู่จากกลุ่มวิธีการเป็นประเภทผู้รับมอบสิทธิ์ที่เข้ากันได้
(เน้นย้ำ) เป็นเรื่องที่ทำให้เข้าใจผิดอย่างมากและเป็นเรื่องที่โชคร้าย ฉันจะคุยกับ Mads เกี่ยวกับการลบคำว่า "เข้ากันได้" ที่นี่
สาเหตุที่ทำให้เข้าใจผิดและเป็นเรื่องโชคร้ายเพราะดูเหมือนว่านี่เป็นการเรียกร้องให้ส่วน 15.2 "ความเข้ากันได้ของตัวแทน" ส่วนที่ 15.2 อธิบายถึงความสัมพันธ์ที่เข้ากันได้ระหว่างวิธีการและประเภทผู้รับมอบสิทธิ์แต่นี่เป็นคำถามเกี่ยวกับความสามารถในการแปลงของกลุ่มวิธีการและประเภทผู้รับมอบสิทธิ์ซึ่งแตกต่างกัน
ตอนนี้เราได้รับสิ่งนั้นหมดแล้วเราสามารถดูหัวข้อ 6.6 ของข้อมูลจำเพาะและดูสิ่งที่เราได้รับ
การทำเช่นความละเอียดเกินที่เราจำเป็นต้องตรวจสอบครั้งแรกซึ่งทับถมเป็นผู้สมัครที่ใช้บังคับ ผู้สมัครสามารถใช้ได้หากอาร์กิวเมนต์ทั้งหมดสามารถแปลงเป็นประเภทพารามิเตอร์ที่เป็นทางการได้โดยปริยาย พิจารณาโปรแกรมเวอร์ชันที่เรียบง่ายนี้:
class Program
{
delegate void D1();
delegate string D2();
static string X() { return null; }
static void Y(D1 d1) {}
static void Y(D2 d2) {}
static void Main()
{
Y(X);
}
}
ลองดูทีละบรรทัด
การแปลงโดยนัยมีอยู่จากกลุ่มวิธีการเป็นประเภทผู้รับมอบสิทธิ์ที่เข้ากันได้
ฉันได้พูดคุยกันแล้วว่าคำว่า "เข้ากันได้" นั้นโชคร้ายที่นี่ กำลังเดินทางไป. เราสงสัยว่าเมื่อทำการแก้ปัญหาโอเวอร์โหลดบน Y (X) เมธอดกลุ่ม X จะแปลงเป็น D1 หรือไม่? มันแปลงเป็น D2?
กำหนดประเภทผู้รับมอบสิทธิ์ D และนิพจน์ E ที่จัดเป็นกลุ่มเมธอดการแปลงโดยนัยจะมีอยู่จาก E เป็น D หาก E มีอย่างน้อยหนึ่งวิธีที่ใช้ได้ [... ] กับรายการอาร์กิวเมนต์ที่สร้างโดยใช้พารามิเตอร์ ประเภทและตัวปรับแต่งของ D ตามที่อธิบายไว้ต่อไปนี้
จนถึงตอนนี้ดีมาก X อาจมีเมธอดที่ใช้ได้กับรายการอาร์กิวเมนต์ของ D1 หรือ D2
แอปพลิเคชันเวลาคอมไพล์ของการแปลงจากกลุ่มเมธอด E ไปเป็นผู้รับมอบสิทธิ์ประเภท D อธิบายไว้ดังต่อไปนี้
บรรทัดนี้ไม่ได้บอกว่ามีอะไรน่าสนใจ
โปรดทราบว่าการมีอยู่ของการแปลงโดยนัยจาก E เป็น D ไม่ได้รับประกันว่าแอปพลิเคชันเวลาคอมไพล์ของการแปลงจะประสบความสำเร็จโดยไม่มีข้อผิดพลาด
เส้นนี้น่าหลงใหล หมายความว่ามีการแปลงโดยนัยที่มีอยู่ แต่อาจกลายเป็นข้อผิดพลาด! นี่เป็นกฎที่แปลกประหลาดของ C # หากต้องการพูดนอกเรื่องสักครู่นี่คือตัวอย่าง:
void Q(Expression<Func<string>> f){}
string M(int x) { ... }
...
int y = 123;
Q(()=>M(y++));
การดำเนินการเพิ่มเป็นสิ่งผิดกฎหมายในแผนภูมินิพจน์ อย่างไรก็ตามแลมด้ายังคงสามารถแปลงเป็นชนิดแผนภูมินิพจน์ได้แม้ว่าจะเคยใช้การแปลงมาแล้วก็ตาม แต่ก็เป็นข้อผิดพลาด! หลักการตรงนี้คือเราอาจต้องการเปลี่ยนกฎของสิ่งที่สามารถไปได้ในแผนภูมินิพจน์ในภายหลัง การเปลี่ยนแปลงกฎระเบียบเหล่านั้นไม่ควรเปลี่ยนกฎระบบการพิมพ์ เราต้องการที่จะบังคับให้คุณที่จะทำให้โปรแกรมของคุณที่ชัดเจนในขณะนี้เพื่อที่ว่าเมื่อเราเปลี่ยนกฎสำหรับต้นไม้แสดงออกในอนาคตที่จะทำให้พวกเขาดีกว่าเราไม่ได้แนะนำการเปลี่ยนแปลงที่จะหมดในความละเอียดเกินพิกัด
อย่างไรก็ตามนี่เป็นอีกตัวอย่างหนึ่งของกฎที่แปลกประหลาดเช่นนี้ การแปลงอาจมีขึ้นเพื่อวัตถุประสงค์ในการแก้ไขปัญหาเกินพิกัด แต่เป็นข้อผิดพลาดในการใช้งานจริง แม้ว่าในความเป็นจริงแล้วนั่นไม่ใช่สถานการณ์ที่เราอยู่ที่นี่
กำลังเดินทางไป:
วิธีการเดียว M ถูกเลือกให้สอดคล้องกับการเรียกใช้เมธอดของรูปแบบ E (A) [... ] รายการอาร์กิวเมนต์ A คือรายการของนิพจน์ซึ่งแต่ละรายการจัดเป็นตัวแปร [... ] ของพารามิเตอร์ที่เกี่ยวข้องในทางการ - พารามิเตอร์ - รายการของ D.
ตกลง. ดังนั้นเราจึงทำการแก้ปัญหาโอเวอร์โหลดบน X เทียบกับ D1 รายการพารามิเตอร์ที่เป็นทางการของ D1 ว่างเปล่าดังนั้นเราจึงทำการแก้ปัญหาโอเวอร์โหลดบน X () และ joy เราพบเมธอด "string X ()" ที่ใช้งานได้ ในทำนองเดียวกันรายการพารามิเตอร์ที่เป็นทางการของ D2 ว่างเปล่า อีกครั้งเราพบว่า "string X ()" เป็นวิธีการที่ใช้ได้เช่นกัน
หลักการที่นี่ก็คือการกำหนดวิธีการเปลี่ยนแปลงกลุ่มต้องเลือกวิธีการออกจากกลุ่มวิธีการใช้ความละเอียดเกินพิกัดและความละเอียดเกินจะไม่พิจารณาผลตอบแทนประเภท
หากอัลกอริทึม [... ] สร้างข้อผิดพลาดข้อผิดพลาดเวลาคอมไพล์จะเกิดขึ้น มิฉะนั้นอัลกอริทึมจะสร้างวิธีที่ดีที่สุดเพียงวิธีเดียวที่มีจำนวนพารามิเตอร์เท่ากับ D และถือว่าการแปลงมีอยู่
มีวิธีเดียวในกลุ่มวิธี X ดังนั้นจึงต้องดีที่สุด เราได้พิสูจน์แล้วว่าประสบความสำเร็จในการแปลงที่มีอยู่จาก X เพื่อ D1 และจาก X เพื่อ D2
ตอนนี้สายนี้เกี่ยวข้องหรือไม่?
เมธอด M ที่เลือกต้องเข้ากันได้กับผู้รับมอบสิทธิ์ประเภท D มิฉะนั้นจะเกิดข้อผิดพลาดเวลาคอมไพล์
จริงๆแล้วไม่ใช่ไม่ใช่ในโปรแกรมนี้ เราไม่เคยไปไกลถึงการเปิดใช้งานสายนี้ เพราะจำไว้ว่าสิ่งที่เรากำลังทำอยู่นี้คือการพยายามแก้ไขปัญหาโอเวอร์โหลดบน Y (X) เรามีผู้สมัครสองคน Y (D1) และ Y (D2) ใช้ได้ทั้งสองอย่าง แบบไหนดีกว่ากัน ? ไม่มีที่ไหนในข้อกำหนดที่เราอธิบายถึงความดีระหว่างการแปลงที่เป็นไปได้ทั้งสองนี้
ตอนนี้เราอาจโต้แย้งได้อย่างแน่นอนว่าการแปลงที่ถูกต้องนั้นดีกว่าการแปลงที่ก่อให้เกิดข้อผิดพลาด จากนั้นจะกล่าวได้อย่างมีประสิทธิภาพในกรณีนี้ว่าการแก้ปัญหาการโอเวอร์โหลดพิจารณาประเภทการส่งคืนซึ่งเป็นสิ่งที่เราต้องการหลีกเลี่ยง คำถามคือหลักการใดดีกว่า: (1) รักษาค่าคงที่ที่ความละเอียดเกินไม่พิจารณาประเภทการส่งคืนหรือ (2) พยายามเลือกการแปลงที่เรารู้ว่าจะใช้ได้ผลกับสิ่งที่เรารู้ว่าจะไม่?
นี่คือการเรียกร้องการตัดสิน ด้วยlambdasเราจะพิจารณาประเภทผลตอบแทนในการแปลงประเภทเหล่านี้ในหัวข้อ 7.4.3.3:
E เป็นฟังก์ชันที่ไม่ระบุชื่อ T1 และ T2 เป็นชนิดผู้รับมอบสิทธิ์หรือประเภทแผนภูมินิพจน์ที่มีรายการพารามิเตอร์เหมือนกันชนิดผลตอบแทนที่สรุปคือ X มีอยู่สำหรับ E ในบริบทของรายการพารามิเตอร์นั้นและการเก็บรักษาอย่างใดอย่างหนึ่งต่อไปนี้:
โชคไม่ดีที่การแปลงกลุ่มวิธีการและการแปลงแลมบ์ดาไม่สอดคล้องกันในแง่นี้ อย่างไรก็ตามฉันสามารถอยู่กับมันได้
อย่างไรก็ตามเราไม่มีกฎ "ดีกว่า" ในการตัดสินว่าการแปลงใดดีกว่า X เป็น D1 หรือ X เป็น D2 ดังนั้นเราจึงให้ข้อผิดพลาดที่ไม่ชัดเจนเกี่ยวกับความละเอียดของ Y (X)