“ this” ในพารามิเตอร์ฟังก์ชัน


89

ดูตัวอย่างโค้ดสำหรับ HtmlHelpers และฉันเห็นการประกาศที่มีลักษณะดังนี้:

public static string HelperName(this HtmlHelper htmlHelper, ...more regular params )

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

คำตอบ:


216

นี่คือไวยากรณ์สำหรับการประกาศวิธีการขยายซึ่งเป็นคุณลักษณะใหม่ของ C # 3.0

วิธีการขยายคือรหัสชิ้นส่วนคอมไพเลอร์ส่วน "มายากล" ซึ่งคอมไพเลอร์ด้วยความช่วยเหลือของ intellisense ใน Visual Studio ทำให้ดูเหมือนว่าวิธีการขยายของคุณมีให้ใช้งานได้จริงเป็นวิธีอินสแตนซ์ของวัตถุที่เป็นปัญหา

ผมขอยกตัวอย่าง

ไม่มีเมธอดในคลาส String ที่มีชื่อว่า GobbleGobble ดังนั้นมาสร้างวิธีการขยาย:

public static class StringExtensions
{
    public static void GobbleGobble(this string s)
    {
        Console.Out.WriteLine("Gobble Gobble, " + s);
    }
}

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

หลังจากประกาศวิธีการข้างต้นคุณสามารถพิมพ์สิ่งนี้ใน Visual Studio:

String s = "Turkey Baster!";
s.

หลังจากจุดรอสำหรับ intellisense และสังเกตว่ามีวิธี GobbleGobble อยู่ที่นั่นกรอกรหัสดังนี้:

String s = "Turkey Baster!";
s.GobbleGobble();

สำคัญ : คลาสที่ประกาศเมธอดส่วนขยายต้องพร้อมใช้งานสำหรับคอมไพลเลอร์และตัวประมวลผล Intellisense เพื่อให้ intellisense แสดงเมธอด หากคุณพิมพ์ GobbleGobble ด้วยตนเองและใช้ทางลัดCtrl+ .จะไม่ช่วยให้คุณใช้คำสั่งลงในไฟล์ได้อย่างถูกต้อง

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

String s = "Turkey Baster!";
s.GobbleGobble();
^     ^
|     +-- the compiler will find this in the StringExtensions class
|
+-- will be used as the first parameter to the method

ดังนั้นโค้ดข้างต้นจะถูกแปลงโดยคอมไพเลอร์เป็น:

String s = "Turkey Baster!";
StringExtensions.GobbleGobble(s);

ดังนั้นในเวลาโทรไม่มีอะไรวิเศษเกี่ยวกับเรื่องนี้มันเป็นเพียงการเรียกร้องให้ใช้วิธีการแบบคงที่

โปรดทราบว่าหากเมธอดส่วนขยายของคุณประกาศพารามิเตอร์มากกว่าหนึ่งพารามิเตอร์ตัวแรกเท่านั้นที่รองรับthisตัวปรับแต่งและส่วนที่เหลือจะต้องถูกระบุเป็นส่วนหนึ่งของการเรียกเมธอดตามปกติ:

public static void GobbleGobble(this string value, string extra)
{                                            |              |
    ...                                      |              |
}                                            |              |
                                             |              |
+--------------------------------------------+              |
|                                                           |
v                                                           |
s.GobbleGobble("extra goes here");                          |
                        ^                                   |
                        |                                   |
                        +-----------------------------------+

มีการเพิ่มวิธีการขยายในส่วนหนึ่งเนื่องจาก Linq โดยที่ไวยากรณ์ Linq ของ C # จะค้นหาวิธีการขยายที่มีชื่อเหมาะสมสำหรับวัตถุที่เล่นซึ่งหมายความว่าคุณสามารถ "แนะนำ" Linq-support ในคลาสประเภทใดก็ได้โดยเพียงแค่ประกาศนามสกุลที่ถูกต้อง วิธีการ แน่นอนว่าการสนับสนุน Linq เต็มรูปแบบนั้นทำงานได้มาก แต่ก็เป็นไปได้

นอกจากนี้วิธีการขยายด้วยตัวเองก็มีประโยชน์มากดังนั้นโปรดอ่านต่อไป

นี่คือลิงค์บางส่วน:


6
ฉันจะเริ่มใช้คำว่า "Gobble Gobble Magic" อย่างแน่นอน
chris

Youtube ทำลายลิงก์อีกครั้งyoutube.com/watch?v=Bz_heb9Rz2gยังคงเวลา @ 1: 00 เป็นต้นไป
Lasse V.Karlsen

เวทมนตร์คอมไพเลอร์ประเภทนี้ทำให้ยากต่อการเรียนรู้ภาษา
Don Dilanga

8

หลังจากวิธีการขยายฉันใช้มันอย่างบ้าคลั่ง .. นี่คือบางส่วนที่ฉันใช้ตลอดเวลา ..

public static T ChangeType<T>(this object obj)
{
  return (T)Convert.ChangeType(obj, typeof(T));
}

ใช้ได้ผลแบบนี้ ..

int i = "123".ChangeType<int>();
bool valid = "bool".ChangeType<bool>();
int id = dataSet.Tables[0].Rows[0]["Id"].ChangeType<int>();

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

public static string ToXml(this object serializableObject)
{
    var aMemStr = new MemoryStream();
    try
    {
        var serializer = new XmlSerializer(serializableObject.GetType());
        serializer.Serialize(new XmlTextWriter(aMemStr, null), serializableObject);
        return Encoding.UTF8.GetString(aMemStr.ToArray());
    }
    finally { if (aMemStr != null) { aMemStr.Dispose(); } }
}

string xml = dataSet.ToXml();

public static T ToObject<T>(this string xmlString)
{
    var aStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString));
    try { return (T)new XmlSerializer(typeof(T)).Deserialize(aStream); }
    finally { if (aStream != null) { aStream.Dispose(); aStream = null; } }
}

DataSet dataSet = xml.ToObject<DataSet>();

6

ใช้สำหรับวิธีการขยาย โดยทั่วไปคุณ 'กาว' ชื่อผู้ช่วยกับวัตถุ htmlHelper เพื่อให้คุณสามารถพูดว่า:

new HtmlHelper().HelperName(...more regular params);

4

นั่นจะเป็นวิธีการขยาย ช่วยให้คุณสามารถ "ขยาย" ชั้นเรียนผ่านวิธีการคงที่ที่อาศัยอยู่นอกคลาสเดิม

ตัวอย่างเช่นสมมติว่าคุณมีวิธีสตริงที่เป็นประโยชน์ซึ่งคุณใช้ตลอดเวลา ...

public int CountAllAs(string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

และคุณเรียกมันว่า ...

string allAs = "aaaA";
int count = CountAllAs(allAs);

นั่นไม่เลวร้ายเกินไป แต่ด้วยการเปลี่ยนแปลงเล็กน้อยคุณสามารถทำให้มันเป็นวิธีการขยายและการโทรจะสวยขึ้นเล็กน้อย:

public static int CountAllAs(this string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

แล้วเรียกมันว่า ...

string allAs = "aaaA";
int count = allAs.CountAllAs();

3

วิธีการต่อ ...

... เป็นวิธีที่ยอดเยี่ยมในการรวมฟังก์ชันต่างๆเช่นหากคุณใช้รูปแบบมัณฑนากรที่ไหนแต่ไม่ต้องเจ็บปวดกับการปรับโครงสร้างโค้ดทั้งหมดของคุณใหม่หรือใช้ชื่อประเภททั่วไป

public static class Extensions
{
     public static string RemoveComma(this string value)
     {
         if (value == null) throw new ArgumentNullException("value");
        return value.Replace(",", "");
    }
}  

คุณจึงสามารถใช้รหัสนี้ได้ทุกที่ในแอปของคุณ

Console.WriteLine(“Hello, My, Friend”.RemoveComma())

>> Hello My Friend

ดังนั้นแอตทริบิวต์คำสั่งนี้จึงหมายถึงประเภทที่ส่วนขยายจะถูก "เพิ่ม" และให้คุณทำงานกับค่าราวกับว่ามันถูกส่งเป็นพารามิเตอร์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.