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

การขยายอินเทอร์เฟซและชนิดทั่วไป

เพิ่มพฤติกรรมให้ชนิดข้อมูลหลายชนิดได้พร้อมกัน

การขยายอินเทอร์เฟซและชนิดทั่วไป เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

การขยายอินเทอร์เฟซ

คุณสามารถเขียนเมธอดส่วนขยายที่มีพารามิเตอร์ this เป็น อินเทอร์เฟซ ได้ ทุกชนิดที่ใช้อินเทอร์เฟซนั้นจะมีเมธอดนี้เพิ่มขึ้นทันที นี่คือวิธีที่ LINQ เพิ่มเมธอดจำนวนมากให้กับ IEnumerable<T>

ส่วนขยายแบบทั่วไปบน IEnumerable

การทำให้เมธอดเป็นแบบทั่วไปเหนือ T และขยาย IEnumerable<T> ทำให้ตัวช่วยนี้ใช้ได้กับลำดับทุกชนิด ทั้งรายการ อาร์เรย์ ผลลัพธ์จากการสืบค้น และอื่น ๆ

using System;
using System.Collections.Generic;

public static class EnumerableExtensions
{
    public static bool IsEmpty<T>(this IEnumerable<T> source)
    {
        foreach (var item in source) return false;
        return true;
    }
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 1, 2, 3 };
        Console.WriteLine(nums.IsEmpty());
        Console.WriteLine(new int[0].IsEmpty());
    }
}

การวนซ้ำในลำดับ

ภายในส่วนขยาย คุณสามารถปฏิบัติต่อพารามิเตอร์เสมือนเป็น IEnumerable<T> ใด ๆ ได้ ที่นี่เราคำนวณผลรวมโดยไม่พึ่งพา LINQ

using System;
using System.Collections.Generic;

public static class EnumerableExtensions
{
    public static int SumValues(this IEnumerable<int> source)
    {
        int total = 0;
        foreach (var n in source) total += n;
        return total;
    }
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 10, 20, 30 };
        Console.WriteLine(nums.SumValues());
    }
}

การส่งคืนลำดับใหม่

ส่วนขยายสามารถส่งคืนลำดับได้เช่นกัน เมื่อใช้ร่วมกับ yield return ส่วนขยายเหล่านี้จะกลายเป็นตัวดำเนินการรูปแบบ LINQ ที่ประเมินเมื่อจำเป็น

using System;
using System.Collections.Generic;

public static class EnumerableExtensions
{
    public static IEnumerable<T> EveryOther<T>(this IEnumerable<T> source)
    {
        bool take = true;
        foreach (var item in source)
        {
            if (take) yield return item;
            take = !take;
        }
    }
}

public class Program
{
    public static void Main()
    {
        var letters = new List<string> { "a", "b", "c", "d", "e" };
        foreach (var l in letters.EveryOther())
            Console.WriteLine(l);
    }
}

ข้อจำกัดของชนิดข้อมูลทั่วไป

คุณสามารถกำหนดข้อจำกัดให้พารามิเตอร์ชนิดข้อมูลทั่วไป เพื่อบังคับให้มีความสามารถที่ต้องการได้ ในที่นี้ where T : IComparable<T> ทำให้เราเปรียบเทียบรายการเพื่อหาค่าสูงสุดได้

using System;
using System.Collections.Generic;

public static class EnumerableExtensions
{
    public static T MaxItem<T>(this IEnumerable<T> source) where T : IComparable<T>
    {
        bool started = false;
        T best = default;
        foreach (var item in source)
        {
            if (!started || item.CompareTo(best) > 0) { best = item; started = true; }
        }
        return best;
    }
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 3, 9, 1, 7 };
        Console.WriteLine(nums.MaxItem());
    }
}

การขยายอินเทอร์เฟซแบบกำหนดเอง

อินเทอร์เฟซที่คุณสร้างขึ้นเองก็ได้รับประโยชน์เช่นกัน ให้กำหนดอินเทอร์เฟซ แล้วเพิ่มพฤติกรรมที่ใช้ร่วมกันผ่านส่วนขยาย แทนการทำซ้ำในทุกคลาสที่นำไปใช้

using System;

public interface INamed { string Name { get; } }

public class Dog : INamed { public string Name => "Rex"; }

public static class NamedExtensions
{
    public static string Greeting(this INamed n) => "Hello, " + n.Name;
}

public class Program
{
    public static void Main()
    {
        var d = new Dog();
        Console.WriteLine(d.Greeting());
    }
}

พารามิเตอร์ชนิดข้อมูลหลายตัว

ส่วนขยายสามารถใช้พารามิเตอร์ชนิดข้อมูลทั่วไปได้หลายตัว ตัวช่วยฉายข้อมูลนี้จะแปลงลำดับโดยใช้ฟังก์ชัน คล้ายกับ Select ใน LINQ

using System;
using System.Collections.Generic;

public static class EnumerableExtensions
{
    public static IEnumerable<TResult> Map<TSource, TResult>(
        this IEnumerable<TSource> source, Func<TSource, TResult> f)
    {
        foreach (var item in source) yield return f(item);
    }
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 1, 2, 3 };
        foreach (var s in nums.Map(n => "#" + n))
            Console.WriteLine(s);
    }
}

การทำงานร่วมกับ LINQ ในตัว

เมธอดส่วนขยายของคุณสามารถทำงานร่วมกับ LINQ ได้ คุณสามารถเชื่อมต่อตัวดำเนินการที่กำหนดเองเข้ากับตัวดำเนินการมาตรฐานในกระบวนการประมวลผลต่อเนื่องเดียวกันได้

using System;
using System.Collections.Generic;
using System.Linq;

public static class EnumerableExtensions
{
    public static IEnumerable<T> EveryOther<T>(this IEnumerable<T> source)
    {
        bool take = true;
        foreach (var item in source) { if (take) yield return item; take = !take; }
    }
}

public class Program
{
    public static void Main()
    {
        var nums = Enumerable.Range(1, 10);
        var result = nums.Where(n => n > 2).EveryOther().ToList();
        Console.WriteLine(string.Join(", ", result));
    }
}

การขยาย IEnumerable ครอบคลุมหลายชนิด

เนื่องจากอาร์เรย์ รายการ พจนานุกรม เซตแฮช และผลลัพธ์จากการสืบค้น ล้วนนำ IEnumerable<T> ไปใช้ ส่วนขยายเดียวจึงครอบคลุมทั้งหมดได้ในคราวเดียว

using System;
using System.Collections.Generic;

public static class EnumerableExtensions
{
    public static int CountItems<T>(this IEnumerable<T> source)
    {
        int n = 0;
        foreach (var item in source) n++;
        return n;
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(new[] { 1, 2, 3 }.CountItems());
        Console.WriteLine(new HashSet<string> { "a", "b" }.CountItems());
    }
}

เหตุผลที่แนวทางนี้ขยายได้ดี

ส่วนขยายของอินเทอร์เฟซช่วยให้คุณสร้างตัวช่วยแบบพหุรูปได้โดยไม่ต้องสืบทอด เขียนตรรกะเพียงครั้งเดียวโดยอิงกับอินเทอร์เฟซ แล้วคลาสที่นำไปใช้ทุกคลาสทั้งในปัจจุบันและอนาคตจะได้รับความสามารถนี้โดยไม่ต้องทำอะไรเพิ่มเติม

using System;
using System.Collections.Generic;

public static class EnumerableExtensions
{
    public static string JoinWith<T>(this IEnumerable<T> source, string sep)
    {
        return string.Join(sep, source);
    }
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 1, 2, 3 };
        Console.WriteLine(nums.JoinWith(" -> "));
    }
}

ลองทำด้วยตัวเอง

สร้างตัวดำเนินการชนิดข้อมูลทั่วไปขนาดเล็กบน IEnumerable<T> แล้วเชื่อมต่อเข้ากับ LINQ สังเกตว่าตัวดำเนินการนี้ทำงานกับลำดับทุกชนิดได้อย่างไร

using System;
using System.Collections.Generic;
using System.Linq;

public static class EnumerableExtensions
{
    public static IEnumerable<T> WithoutDuplicatesByKey<T, TKey>(
        this IEnumerable<T> source, Func<T, TKey> keySelector)
    {
        var seen = new HashSet<TKey>();
        foreach (var item in source)
            if (seen.Add(keySelector(item))) yield return item;
    }
}

public class Program
{
    public static void Main()
    {
        var words = new[] { "apple", "avocado", "banana", "cherry", "blueberry" };
        var firstPerLetter = words.WithoutDuplicatesByKey(w => w[0]);
        Console.WriteLine(string.Join(", ", firstPerLetter));
    }
}

ตรวจสอบอย่างรวดเร็ว

ลองคิดดูว่าส่วนขยายรูปแบบ LINQ ถูกประกาศอย่างไร

สรุปทบทวน

การขยายอินเทอร์เฟซ โดยเฉพาะ IEnumerable<T> เป็นรากฐานของการเขียนโปรแกรมรูปแบบ LINQ

  • ทำให้เมธอดเป็นชนิดข้อมูลทั่วไป และใช้อินเทอร์เฟซเป็นชนิด this
  • ใช้ yield return เพื่อสร้างตัวดำเนินการที่ประเมินเมื่อจำเป็น
  • ใช้ข้อจำกัดแบบ where เพื่อบังคับให้มีความสามารถ เช่น IComparable<T>
  • ส่วนขยายของอินเทอร์เฟซเดียวครอบคลุมคลาสที่นำไปใช้ทั้งหมด รวมถึงคลาสที่จะมีในอนาคต

คำถามที่พบบ่อย

บทเรียน “การขยายอินเทอร์เฟซและชนิดทั่วไป” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การขยายอินเทอร์เฟซและชนิดทั่วไป” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การขยายอินเทอร์เฟซและชนิดทั่วไป”

เพิ่มพฤติกรรมให้ชนิดข้อมูลหลายชนิดได้พร้อมกัน คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การขยายอินเทอร์เฟซและชนิดทั่วไป” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม

ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

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

  1. การกำหนดเมธอดส่วนขยาย
  2. การขยายอินเทอร์เฟซและชนิดทั่วไป
  3. การค้นหาเมธอดส่วนขยาย
  4. การออกแบบส่วนขยายที่ดี
← กลับไปที่ C# Academy