อะไรคือความแตกต่างระหว่าง <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>เป็นตัวอย่างที่แปลกประหลาดถ้าคุณต้องการobjects คุณไม่จำเป็นต้องใช้ยาชื่อสามัญ
สำหรับการจดจำการใช้งาน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