0Pricing
C# Academy · บทเรียน

ความแปรผัน (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

ตรวจสอบอย่างรวดเร็ว: คีย์เวิร์ดใดใช้ระบุพารามิเตอร์ชนิดแบบโคเวเรียนต์บนอินเทอร์เฟซหรือ delegate

ทบทวน

ทบทวน: ใช้ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เมธอด/ชนิดแบบเจเนอริกและข้อจำกัด
  2. ความแปรผัน (in/out) กับอินเทอร์เฟซและผู้รับมอบหมาย
  3. ชนิดอ้างอิงที่เป็นค่าว่างได้ (ความตระหนักรู้) และคำอธิบายประกอบ (รูปแบบ C# 6)
← กลับไปที่ C# Academy