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

การค้นหาเมธอดส่วนขยาย

ทำความเข้าใจว่าคอมไพเลอร์ค้นหาส่วนขยายอย่างไร

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

คอมไพเลอร์ค้นหาส่วนขยายอย่างไร

เมื่อคุณเขียน value.Method() แล้วไม่มีเมธอดของอินสแตนซ์ที่ตรงกัน คอมไพเลอร์จะค้นหาเมธอดส่วนขยาย แต่จะพิจารณาเฉพาะส่วนขยายที่มีเนมสเปซเจ้าของอยู่ในขอบเขตผ่านคำสั่ง using เท่านั้น

คำสั่งนำเข้าเนมสเปซทำให้ส่วนขยายอยู่ในขอบเขต

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

using System;
using MyHelpers; // brings StringExtensions into scope

namespace MyHelpers
{
    public static class StringExtensions
    {
        public static string Reverse(this string s)
        {
            var arr = s.ToCharArray();
            Array.Reverse(arr);
            return new string(arr);
        }
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("hello".Reverse());
    }
}

ตรวจสอบเมธอดของอินสแตนซ์ก่อน

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

using System;
using System.Collections.Generic;

public static class ListExt
{
    // Ignored: List<int> already has Add(int)
    public static void Add(this List<int> list, int a, int b)
        => list.Add(a + b);
}

public class Program
{
    public static void Main()
    {
        var list = new List<int>();
        list.Add(5); // the built-in instance Add wins for this signature
        Console.WriteLine(list[0]);
    }
}

เลือกเนมสเปซที่อยู่ใกล้กว่า

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

using System;

namespace Outer
{
    public static class A { public static string Tag(this int n) => "A" + n; }

    namespace Inner
    {
        public static class B { public static string Tag(this int n) => "B" + n; }

        public class Program
        {
            public static void Main()
            {
                // B is in the nearer (Inner) namespace, so it is preferred
                Console.WriteLine(7.Tag());
            }
        }
    }
}

ระบุให้ชัดเจนด้วยการเรียกแบบสแตติก

เมื่อส่วนขัดแย้งกันหรือคุณต้องการระบุให้ชัดเจน ให้เรียกเมธอดแบบสแตติกโดยตรงด้วยชื่อคลาสแบบเต็ม วิธีนี้จะข้ามกระบวนการค้นหาเมธอดส่วนขยายทั้งหมด

using System;

public static class FormatExt
{
    public static string Bracket(this string s) => "[" + s + "]";
}

public class Program
{
    public static void Main()
    {
        // Explicit static call, no ambiguity possible
        Console.WriteLine(FormatExt.Bracket("x"));
    }
}

การเลือกเมธอดหลายรูปแบบระหว่างส่วนขยาย

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

using System;

public static class PrintExt
{
    public static string Describe(this int n) => "int:" + n;
    public static string Describe(this string s) => "str:" + s;
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(42.Describe());
        Console.WriteLine("hi".Describe());
    }
}

การอนุมานชนิดข้อมูลระหว่างการค้นหา

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

using System;
using System.Collections.Generic;

public static class SeqExt
{
    public static T FirstItem<T>(this IEnumerable<T> source)
    {
        foreach (var item in source) return item;
        throw new InvalidOperationException("empty");
    }
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 5, 6, 7 };
        // T inferred as int from the List<int> receiver
        Console.WriteLine(nums.FirstItem());
    }
}

คำสั่ง using ทั่วทั้งโครงการและการนำเข้าโดยนัย

C# สมัยใหม่สามารถประกาศคำสั่ง global using เพื่อให้เนมสเปซอยู่ในขอบเขตทั่วทั้งโครงการ วิธีนี้ทำให้ไลบรารีส่วนขยายที่ใช้ร่วมกันพร้อมใช้งานได้ทุกที่โดยไม่ต้องเขียนคำสั่งนำเข้าซ้ำ

using System;

// In a real project a separate file might say: global using MyHelpers;
namespace MyHelpers
{
    public static class IntExt { public static int Twice(this int n) => n * 2; }
}

public class Program
{
    public static void Main()
    {
        // Works here because MyHelpers is referenced explicitly
        Console.WriteLine(MyHelpers.IntExt.Twice(8));
    }
}

เมื่อชนิดของตัวรับมีความสำคัญ

การค้นหาขึ้นอยู่กับชนิดแบบสแตติกของตัวรับ ไม่ใช่ชนิดขณะทำงาน ส่วนขยายที่ประกาศไว้สำหรับชนิดพื้นฐานจะใช้งานได้แม้ตัวแปรจะเก็บอินสแตนซ์ของชนิดที่สืบทอดมา เว้นแต่จะมีส่วนขยายที่เฉพาะเจาะจงกว่าอยู่ในขอบเขต

using System;

public class Animal { }
public class Cat : Animal { }

public static class AnimalExt
{
    public static string Kind(this Animal a) => "animal";
}

public class Program
{
    public static void Main()
    {
        Animal a = new Cat();
        // Chosen by static type Animal
        Console.WriteLine(a.Kind());
    }
}

แบบจำลองทางความคิดสำหรับการค้นหา

ลองนึกถึงลำดับดังนี้: (1) เมธอดของอินสแตนซ์ จากนั้น (2) เมธอดส่วนขยายจากเนมสเปซที่นำเข้า โดยเริ่มจากเนมสเปซที่อยู่ใกล้ที่สุด และสุดท้าย (3) การเลือกเมธอดจากตัวเลือกที่มี การทราบลำดับนี้ช่วยอธิบายผลลัพธ์ที่ดูน่าประหลาดใจได้เกือบทั้งหมด

using System;

public static class Ext
{
    public static string Wrap(this string s) => "<" + s + ">";
}

public class Program
{
    public static void Main()
    {
        // No instance Wrap exists, so the extension is used
        Console.WriteLine("node".Wrap());
    }
}

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

กำหนดส่วนขยายในเนมสเปซหนึ่ง นำเข้าเนมสเปซนั้น แล้วเรียกใช้ส่วนขยาย จากนั้นเรียกเมธอดเดียวกันอย่างชัดเจนในฐานะเมธอดแบบสแตติก เพื่อดูว่าทั้งสองวิธีทำงานได้

using System;
using Text.Helpers;

namespace Text.Helpers
{
    public static class StringExtensions
    {
        public static int Vowels(this string s)
        {
            int count = 0;
            foreach (var c in s.ToLower())
                if ("aeiou".IndexOf(c) >= 0) count++;
            return count;
        }
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("education".Vowels());
        Console.WriteLine(Text.Helpers.StringExtensions.Vowels("education"));
    }
}

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

ลองพิจารณาว่าอะไรทำให้เมธอดส่วนขยายมองเห็นได้

สรุปทบทวน

การค้นหาเมธอดส่วนขยายเป็นไปตามลำดับที่ชัดเจน

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

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

บทเรียน “การค้นหาเมธอดส่วนขยาย” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การค้นหาเมธอดส่วนขยาย”

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

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

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

บทเรียน “การค้นหาเมธอดส่วนขยาย” ใช้เวลานานแค่ไหน

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

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

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

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

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