"This" trong tham số hàm


88

Xem xét một số ví dụ mã cho HtmlHelpers và tôi thấy các khai báo giống như sau:

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

Tôi không thể nhớ mình đã nhìn thấy loại cấu trúc này ở bất kỳ nơi nào khác - ai đó có thể giải thích mục đích của "cái này" không? Tôi nghĩ rằng bằng cách khai báo một cái gì đó public static có nghĩa là lớp không cần phải được khởi tạo - vậy "this" trong trường hợp này là gì?

Câu trả lời:


212

Đây là cú pháp khai báo các phương thức mở rộng, một tính năng mới của C # 3.0.

Phương thức mở rộng là mã phần, "ma thuật" của trình biên dịch phần, trong đó trình biên dịch với sự trợ giúp của intellisense trong Visual Studio làm cho phương thức mở rộng của bạn thực sự có sẵn dưới dạng một phương thức thể hiện trên đối tượng được đề cập.

Để tôi lấy một ví dụ.

Không có phương thức nào trên lớp String được đặt tên là GobbleGobble, vì vậy hãy tạo một phương thức mở rộng:

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

Tên lớp chỉ là quy ước đặt tên của tôi, không nhất thiết phải đặt tên như vậy, nhưng nó phải tĩnh, cũng như phương thức.

Sau khi khai báo phương thức trên, bạn có thể, trong Visual Studio, nhập vào:

String s = "Turkey Baster!";
s.

sau dấu chấm, hãy đợi intellisense và nhận thấy có một phương thức GobbleGobble ở đó, hãy hoàn thành đoạn mã như sau:

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

Quan trọng : Lớp nơi phương thức mở rộng được khai báo phải có sẵn cho trình biên dịch và trình xử lý intellisense để intellisense hiển thị phương thức. Nếu bạn nhập GobbleGobble theo cách thủ công và sử dụng phím tắt Ctrl+ ., nó sẽ không giúp bạn sử dụng đúng các lệnh vào tệp.

Lưu ý rằng tham số của phương thức đã biến mất. Trình biên dịch sẽ âm thầm di chuyển xung quanh các bit quan trọng, đó là:

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

Do đó, đoạn mã trên sẽ được trình biên dịch chuyển đổi thành:

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

Vì vậy, tại thời điểm gọi, không có gì kỳ diệu về nó, nó chỉ là một cuộc gọi đến một phương thức tĩnh.

Lưu ý rằng nếu phương thức mở rộng của bạn khai báo nhiều hơn một tham số, chỉ tham số đầu tiên hỗ trợ công cụ thissửa đổi và phần còn lại phải được chỉ định như một phần của lệnh gọi phương thức như bình thường:

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

Các phương thức mở rộng đã được thêm vào một phần do Linq, trong đó cú pháp Linq của C # sẽ tìm kiếm các phương thức mở rộng được đặt tên thích hợp cho các đối tượng đang chơi, có nghĩa là bạn có thể "giới thiệu" Linq-support vào bất kỳ loại lớp nào bằng cách khai báo đúng phần mở rộng các phương pháp. Tất nhiên, hỗ trợ Linq đầy đủ là rất nhiều công việc, nhưng nó hoàn toàn có thể.

Ngoài ra, các phương pháp mở rộng thực sự hữu ích, vì vậy hãy đọc nó.

Đây là một số liên kết:


6
Tôi chắc chắn sẽ bắt đầu sử dụng thuật ngữ "Gobble Gobble Magic".
chris

Youtube đã phá vỡ liên kết một lần nữa, youtube.com/watch?v=Bz_heb9Rz2g , vẫn ở @ 1: 00 trở đi.
Lasse V. Karlsen

Những phép thuật trình biên dịch kiểu này làm cho việc học một ngôn ngữ trở nên khó khăn.
Don Dilanga

8

Sau các phương thức mở rộng, tôi đã sử dụng chúng như điên .. đây là một vài phương pháp tôi sử dụng liên tục ..

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

Hoạt động như thế này ..

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

Vâng, nó hiển thị trên mọi đối tượng, có thể gây khó chịu nhưng vì tôi sử dụng điều này cho khá nhiều loại dữ liệu, nó sẽ giúp chỉ đính kèm nó một đối tượng thay vì sao chép nó cho mọi loại dữ liệu có thể.

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

Nó được sử dụng cho các phương thức mở rộng. Về cơ bản, bạn 'dán' Tên người trợ giúp vào đối tượng htmlHelper để bạn có thể nói:

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

4

Đó sẽ là một Phương pháp Mở rộng. Chúng cho phép bạn "mở rộng" một lớp thông qua các phương thức tĩnh nằm bên ngoài lớp gốc.

Ví dụ: giả sử bạn có một phương thức chuỗi hữu ích mà bạn luôn sử dụng ...

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

Và bạn gọi nó là ...

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

Điều đó không quá tệ. Nhưng với một thay đổi nhỏ, bạn có thể biến nó thành một phương thức Extension và cuộc gọi sẽ đẹp hơn một chút:

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

Và sau đó gọi nó là ...

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

3

Các phương pháp mở rộng ...

... là một cách tuyệt vời để bao gồm chức năng như nếu bạn sử dụng mẫu trang trí , nhưng không cần phải cấu trúc lại tất cả mã của bạn hoặc sử dụng tên khác của một loại thông dụng.

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

Vì vậy, bạn có thể sử dụng mã này, ở bất kỳ đâu trong ứng dụng của bạn.

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

>> Hello My Friend

Vì vậy, thuộc tính lệnh này có nghĩa là loại mà phần mở rộng sẽ được “thêm vào” và cho phép bạn làm việc với giá trị như thể nó được truyền dưới dạng tham số.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.