อะไรคือความแตกต่างระหว่าง <out T>
และ<T>
คืออะไร? ตัวอย่างเช่น:
public interface IExample<out T>
{
...
}
เมื่อเทียบกับ
public interface IExample<T>
{
...
}
อะไรคือความแตกต่างระหว่าง <out T>
และ<T>
คืออะไร? ตัวอย่างเช่น:
public interface IExample<out T>
{
...
}
เมื่อเทียบกับ
public interface IExample<T>
{
...
}
คำตอบ:
out
คำหลักใน generics ใช้เพื่อแสดงว่า T ประเภทในอินเตอร์เฟซเป็น covariant ดูความแปรปรวนร่วมและความแปรปรวนสำหรับรายละเอียด
IEnumerable<out T>
ตัวอย่างคลาสสิกเป็น เนื่องจากIEnumerable<out T>
เป็น covariant คุณได้รับอนุญาตให้ทำสิ่งต่อไปนี้:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
บรรทัดที่สองด้านบนจะล้มเหลวหากนี่ไม่ใช่ค่าแปรปรวนแม้ว่ามันควรจะทำงานได้ดีเนื่องจากสตริงเกิดขึ้นจากวัตถุ ก่อนความแปรปรวนในอินเทอร์เฟซทั่วไปให้กับ C # และ VB.NET (ใน. NET 4 ที่มี VS 2010) นี่เป็นข้อผิดพลาดเวลาในการรวบรวม
หลังจาก .NET 4 IEnumerable<T>
ที่ถูกทำเครื่องหมาย covariant IEnumerable<out T>
และกลายเป็น เนื่องจากIEnumerable<out T>
ใช้องค์ประกอบภายในเท่านั้นและไม่เคยเพิ่ม / เปลี่ยนแปลงมันจึงปลอดภัยที่จะปฏิบัติต่อคอลเลกชันที่นับได้ของสตริงเป็นคอลเลกชันของวัตถุที่นับไม่ได้ซึ่งหมายความว่ามันแปรปรวนร่วม covariant
สิ่งนี้จะไม่ทำงานกับประเภทที่คล้ายIList<T>
กันเนื่องจากIList<T>
มีAdd
วิธีการ สมมติว่าสิ่งนี้จะได้รับอนุญาต:
IList<string> strings = new List<string>();
IList<object> objects = strings; // NOTE: Fails at compile time
จากนั้นคุณสามารถโทร:
objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object
แน่นอนว่าสิ่งนี้จะล้มเหลว - ดังนั้นจึงIList<T>
ไม่สามารถทำเครื่องหมายโควาเรียนต์ได้
นอกจากนี้ยังมี btw ตัวเลือกสำหรับin
- ซึ่งถูกใช้โดยสิ่งต่าง ๆ เช่นอินเทอร์เฟซการเปรียบเทียบ IComparer<in T>
ตัวอย่างเช่นทำงานในทางตรงกันข้าม คุณสามารถใช้คอนกรีตIComparer<Foo>
โดยตรงเป็นIComparer<Bar>
ถ้าBar
เป็น subclass ของFoo
เพราะIComparer<in T>
อินเตอร์เฟซที่contravariant
Image
เป็นคลาสนามธรรม;) คุณสามารถทำได้new List<object>() { Image.FromFile("test.jpg") };
โดยไม่มีปัญหาหรือคุณสามารถทำได้new List<object>() { new Bitmap("test.jpg") };
เช่นกัน ปัญหาของคุณคือnew Image()
ไม่ได้รับอนุญาต (คุณทำไม่ได้var img = new Image();
)
IList<object>
เป็นตัวอย่างที่แปลกประหลาดถ้าคุณต้องการobject
s คุณไม่จำเป็นต้องใช้ยาชื่อสามัญ
สำหรับการจดจำการใช้งานin
และout
คำหลักได้อย่างง่ายดาย(เช่นความแปรปรวนร่วมและความแปรปรวน) เราสามารถจำลองการสืบทอดเป็นภาพ:
String : Object
Bar : Foo
พิจารณา,
class Fruit {}
class Banana : Fruit {}
interface ICovariantSkinned<out T> {}
interface ISkinned<T> {}
และฟังก์ชั่น
void Peel(ISkinned<Fruit> skinned) { }
void Peel(ICovariantSkinned<Fruit> skinned) { }
ฟังก์ชั่นที่ยอมรับICovariantSkinned<Fruit>
จะสามารถยอมรับICovariantSkinned<Fruit>
หรือICovariantSkinned<Bananna>
เพราะICovariantSkinned<T>
เป็นอินเตอร์เฟซ covariant และBanana
เป็นประเภทของFruit
,
ฟังก์ชั่นที่ยอมรับISkinned<Fruit>
จะสามารถยอมรับISkinned<Fruit>
ได้เท่านั้น
" out T
" หมายถึงประเภทT
นั้นคือ "covariant" ที่ จำกัดT
ให้ปรากฏเฉพาะเป็นค่าที่ส่งคืน (ขาออก) ในวิธีการของคลาสทั่วไปอินเทอร์เฟซหรือวิธีการ ความหมายคือที่คุณสามารถโยนประเภท / อินเตอร์เฟซ / T
วิธีการเพื่อให้เทียบเท่ากับซุปเปอร์ประเภทของ
เช่นสามารถที่จะโยนICovariant<out Dog>
ICovariant<Animal>
out
บังคับใช้ที่T
สามารถส่งคืนได้เท่านั้นจนกว่าฉันจะอ่านคำตอบนี้ แนวคิดทั้งหมดนี้สมเหตุสมผลมากขึ้นในขณะนี้!
จากลิงค์ที่คุณโพสต์ ....
สำหรับพารามิเตอร์ประเภททั่วไป, ออกระบุคำหลักที่พารามิเตอร์ชนิดคือ covariant
แก้ไข : อีกครั้งจากลิงค์ที่คุณโพสต์
สำหรับข้อมูลเพิ่มเติมดูความแปรปรวนร่วมและความแปรปรวน (C # และ Visual Basic) http://msdn.microsoft.com/en-us/library/ee207183.aspx