มีสองสิ่งที่คุณต้องรู้เพื่อทำความเข้าใจพฤติกรรมนี้
- ผู้รับมอบสิทธิ์ทั้งหมดมาจาก
System.Delegate
แต่ผู้รับมอบสิทธิ์ที่แตกต่างกันมีประเภทที่แตกต่างกันดังนั้นจึงไม่สามารถมอบหมายให้กันได้
- ภาษา C # ให้การจัดการพิเศษสำหรับการกำหนดวิธีการหรือแลมบ์ดาจะเป็นผู้รับมอบสิทธิ์
เนื่องจากผู้รับมอบสิทธิ์ที่แตกต่างกันมีประเภทที่แตกต่างกันนั่นหมายความว่าคุณไม่สามารถมอบหมายผู้รับมอบสิทธิ์ให้แก่ตัวแทนประเภทหนึ่ง
ตัวอย่างเช่นกำหนด:
delegate void test1(int i);
delegate void test2(int i);
แล้ว:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
บรรทัดแรกข้างต้นรวบรวม OK เพราะมันใช้การจัดการพิเศษสำหรับการกำหนดแลมบ์ดาหรือวิธีการให้กับผู้ได้รับมอบหมาย
ในความเป็นจริงบรรทัดนี้เขียนใหม่ได้อย่างมีประสิทธิภาพเช่นนี้โดยคอมไพเลอร์:
test1 a = new test1(Console.WriteLine);
บรรทัดที่สองด้านบนไม่ได้รวบรวมเนื่องจากพยายามกำหนดอินสแตนซ์ของประเภทหนึ่งให้เป็นประเภทอื่นที่เข้ากันไม่ได้
เท่าที่ไปประเภทไม่มีการกำหนดที่เข้ากันได้ระหว่างtest1
และtest2
เพราะพวกเขาเป็นประเภทที่แตกต่างกัน
ถ้าช่วยให้คิดได้ให้พิจารณาลำดับชั้นของคลาสนี้:
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
รหัสต่อไปนี้จะไม่รวบรวมแม้ว่าTest1
และได้Test2
รับมาจากคลาสฐานเดียวกัน:
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
สิ่งนี้อธิบายว่าทำไมคุณไม่สามารถกำหนดประเภทผู้ได้รับมอบหมายให้แก่ประเภทอื่น นั่นเป็นเพียงภาษา C # ปกติ
อย่างไรก็ตามสิ่งสำคัญคือการเข้าใจว่าทำไมคุณจึงได้รับอนุญาตให้กำหนดวิธีการหรือแลมบ์ดาให้กับตัวแทนที่เข้ากันได้ ดังที่กล่าวไว้ข้างต้นนี่เป็นส่วนหนึ่งของการสนับสนุนภาษา C # สำหรับผู้ได้รับมอบหมาย
ดังนั้นในที่สุดก็จะตอบคำถามของคุณ:
เมื่อคุณใช้Invoke()
คุณกำลังกำหนดวิธีการโทรไปยังผู้รับมอบสิทธิ์โดยใช้การจัดการภาษา C # พิเศษสำหรับการกำหนดวิธีการหรือ lambdas ให้กับผู้ร่วมประชุมแทนที่จะพยายามกำหนดประเภทที่เข้ากันไม่ได้ - ดังนั้นจึงรวบรวม OK
เพื่อความชัดเจนรหัสที่รวบรวมใน OP ของคุณ:
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
จริง ๆ แล้วเป็นการแปลงมโนภาพเป็นบางสิ่งเช่น:
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
ในขณะที่รหัสความล้มเหลวพยายามที่จะกำหนดระหว่างสองประเภทที่เข้ากันไม่ได้:
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}