ความแปรผัน (in/out) กับอินเทอร์เฟซและผู้รับมอบหมาย
ทำความเข้าใจความแปรผันของ C#: out สำหรับผู้ผลิต (โคแวเรียนซ์) และ in สำหรับผู้บริโภค (คอนทราแวเรียนซ์) บนอินเทอร์เฟซและผู้รับมอบหมาย
ความแปรผัน (in/out) กับอินเทอร์เฟซและผู้รับมอบหมาย เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 3 บทเรียน
ภาพรวมความแปรผันของชนิดข้อมูล
ความแปรผันของชนิดข้อมูล ทำให้อินเทอร์เฟซหรือตัวมอบหมายแบบทั่วไปทำงานร่วมกับการสืบทอดได้
- out = ความแปรผันร่วม (ผู้สร้างข้อมูล)
- in = ความแปรผันย้อนกลับ (ผู้รับข้อมูล)
- ปลอดภัยเมื่อส่วนติดต่อสร้างหรือรับค่า T เพียงอย่างใดอย่างหนึ่ง
ตัวอย่าง Covariance
IEnumerable<out T> เป็นแบบโคเวเรียนต์: สามารถใช้ลำดับของแมวในตำแหน่งที่คาดว่าจะเป็นลำดับของสัตว์ได้
using System;
using System.Collections.Generic;
public class Animal { public virtual string Name() { return "animal"; } }
public class Cat : Animal { public override string Name() { return "cat"; } }
public class Program
{
static void PrintAll(IEnumerable<Animal> animals)
{
foreach (Animal a in animals)
{
Console.WriteLine(a.Name());
}
}
public static void Main(string[] args)
{
List<Cat> cats = new List<Cat>();
cats.Add(new Cat());
// IEnumerable<Cat> -> IEnumerable<Animal> is allowed (out T)
PrintAll(cats);
}
}
ตัวอย่าง Contravariance
IComparer<in T> เป็นแบบคอนทราเวเรียนต์: ตัวเปรียบเทียบสำหรับ Animal ก็ใช้กับ Cat ได้เช่นกัน เพราะทำหน้าที่เพียง รับค่า T
using System;
using System.Collections.Generic;
public class Animal { public string N; public Animal(string n){ N=n; } }
public class Cat : Animal { public Cat(string n) : base(n) {} }
// Comparer can compare any Animals
public class AnimalNameComparer : IComparer<Animal>
{
public int Compare(Animal x, Animal y)
{
return string.Compare(x == null ? "" : x.N, y == null ? "" : y.N, StringComparison.Ordinal);
}
}
public class Program
{
public static void Main(string[] args)
{
List<Cat> cats = new List<Cat>();
cats.Add(new Cat("Miso"));
cats.Add(new Cat("Ada"));
// IComparer<Animal> can be used as IComparer<Cat> (in T)
cats.Sort(new AnimalNameComparer());
foreach (Cat c in cats) Console.WriteLine(c.N);
}
}
ความแปรผันของ Delegate
Delegate ก็มีความแปรผันเช่นกัน: Func<out TResult> (ผู้ผลิต) และ Action<in T> (ผู้บริโภค)
using System;
public class Animal { public virtual string Speak(){ return "???"; } }
public class Cat : Animal { public override string Speak(){ return "meow"; } }
public class Program
{
static Animal MakeAnimal() { return new Animal(); }
static void HandleAnimal(Animal a) { Console.WriteLine(a.Speak()); }
public static void Main(string[] args)
{
// Func<Cat> can be used where Func<Animal> is expected? Yes, because TResult is out.
Func<Animal> maker = new Func<Cat>(delegate { return new Cat(); });
Console.WriteLine(maker().Speak());
// Action<Animal> can be used where Action<Cat> is expected? Yes, because T is in.
Action<Cat> catSink = new Action<Animal>(HandleAnimal);
catSink(new Cat());
}
}
อินเทอร์เฟซแบบแปรผันที่กำหนดเอง
กฎการออกแบบ: กำหนดพารามิเตอร์ที่ใช้เฉพาะสำหรับการผลิตเป็น out และพารามิเตอร์ที่ใช้เฉพาะสำหรับการบริโภคเป็น in เพื่อให้แปลงชนิดได้อย่างปลอดภัย
using System;
// Producer-only interface: out T
public interface ISource<out T>
{
T Get();
}
// Consumer-only interface: in T
public interface ISink<in T>
{
void Put(T item);
}
public class Animal { public string N; }
public class Cat : Animal { }
public class CatSource : ISource<Cat>
{
public Cat Get() { return new Cat(); }
}
public class AnimalSink : ISink<Animal>
{
public void Put(Animal a) { Console.WriteLine("Got animal"); }
}
public class Program
{
public static void Main(string[] args)
{
ISource<Animal> animals = new CatSource(); // out T allows upcast
ISink<Cat> cats = new AnimalSink(); // in T allows down-assign
animals.Get();
cats.Put(new Cat());
}
}
เคล็ดลับเรื่องความแปรผัน
เคล็ดลับ:
- พารามิเตอร์ out ต้องปรากฏได้เฉพาะในตำแหน่งผลลัพธ์ (ชนิดผลลัพธ์หรือจุดที่เป็นโคเวเรียนต์) เท่านั้น
- พารามิเตอร์ in ต้องปรากฏได้เฉพาะในตำแหน่งอินพุต (พารามิเตอร์ของเมธอด) เท่านั้น
- อย่าผสมการผลิตและการบริโภคสำหรับ T เดียวกันเมื่อประกาศความแปรผัน
- ความแปรผันใช้ได้กับอินเทอร์เฟซและ delegate ไม่ใช่คลาส
คีย์เวิร์ด Covariance
ทบทวน
ทบทวน: ใช้ out สำหรับผู้ผลิต (โคเวเรียนซ์) และใช้ in สำหรับผู้บริโภค (คอนทราเวเรียนซ์) บนอินเทอร์เฟซและ delegate ออกแบบ API ให้ทำงานทางเดียวเพื่อให้แปลงชนิดได้อย่างปลอดภัย
คำถามที่พบบ่อย
บทเรียน “ความแปรผัน (in/out) กับอินเทอร์เฟซและผู้รับมอบหมาย” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ความแปรผัน (in/out) กับอินเทอร์เฟซและผู้รับมอบหมาย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 3 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ความแปรผัน (in/out) กับอินเทอร์เฟซและผู้รับมอบหมาย”
ทำความเข้าใจความแปรผันของ C#: out สำหรับผู้ผลิต (โคแวเรียนซ์) และ in สำหรับผู้บริโภค (คอนทราแวเรียนซ์) บนอินเทอร์เฟซและผู้รับมอบหมาย คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 3 บทเรียน
บทเรียน “ความแปรผัน (in/out) กับอินเทอร์เฟซและผู้รับมอบหมาย” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม
ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เมธอด/ชนิดแบบเจเนอริกและข้อจำกัด
- ความแปรผัน (in/out) กับอินเทอร์เฟซและผู้รับมอบหมาย
- ชนิดอ้างอิงที่เป็นค่าว่างได้ (ความตระหนักรู้) และคำอธิบายประกอบ (รูปแบบ C# 6)