2010-06-15 52 views
65

Nhìn vào một số ví dụ mã cho HtmlHelpers, và tôi thấy tờ khai mà hình như:"này" trong tham số chức năng

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

Tôi không thể nhớ nhìn thấy kiểu này xây dựng bất kỳ nơi nào khác - ai đó có thể giải thích sự mục đích của "điều này"? Tôi nghĩ rằng bằng cách tuyên bố một cái gì đó tĩnh công cộng có nghĩa là các lớp học không cần phải được instantiated - vì vậy những gì là "này" trong trường hợp này?

Trả lời

162

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

Một phương pháp mở rộng là một phần, phần biên dịch "ma thuật", nơi trình biên dịch với sự trợ giúp của intellisense trong Visual Studio làm cho nó xuất hiện rằng phương pháp mở rộng của bạn thực sự có sẵn như là một phương pháp dụ trên đối tượng trong câu hỏi.

Hãy để tôi đưa ra một ví dụ.

Không có phương pháp trên lớp String có tên GobbleGobble, vì vậy chúng ta hãy tạo ra một phương pháp khuyến nô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, nó không phải là cần thiết để đặt tên cho nó như vậy, nhưng nó phải là tĩnh, cũng như phương pháp.

Sau khi tuyên bố các phương pháp trên, bạn có thể, trong Visual Studio, gõ này:

String s = "Turkey Baster!"; 
s. 

sau dấu chấm, chờ IntelliSense, và nhận thấy có một phương pháp GobbleGobble có, hãy điền mã như thế này:

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

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

Lưu ý rằng tham số cho phương pháp đã 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 đó, các mã trên sẽ được biến đổi bởi trình biên dịch như sau:

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

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

Lưu ý rằng nếu phương pháp khuyến nông của mình tuyên bố nhiều hơn một tham số, chỉ là người đầu tiên ủng hộ sửa đổi this, và phần còn lại phải được xác định như là một phần của cuộc gọi phương pháp như bình thường:

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

phương pháp mở rộng là được thêm 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, nghĩa là bạn có thể "giới thiệu" hỗ trợ LINQ vào bất kỳ loại lớp nào bằng cách khai báo đúng phương thức mở rộng. Tất nhiên, hỗ trợ đầy đủ LINQ là rất nhiều công việc, nhưng nó là có thể.

Ngoài ra, các phương pháp mở rộng của chính chúng thực sự hữu ích, do đó hãy đọc nó.

Dưới đây là một số liên kết:

+2

Thưa bạn, bạn không nên trả lời dù sao, bạn nên làm cho tôi một trình chỉnh sửa biểu đồ mới tốt đẹp! :) (oh, và cảm ơn bạn vì lời khen ngợi loại sir!) –

+2

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

+0

Youtube đã ngắt liên kết một lần nữa, http://www.youtube.com/watch?v=Bz_heb9Rz2g, vẫn ở @ 1: 00 trở đi. –

6

Nó được sử dụng cho extensionmethods. Về cơ bản, bạn 'gắn' Trình trợ giúp cho đố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 tồn tại bên ngoài lớp gốc.

Ví dụ, nói rằng bạn có một phương pháp chuỗi hữu ích mà bạn sử dụng tất cả thời gian ...

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); 

Đó không phải là quá xấu. Nhưng với một sự thay đổi nhỏ, bạn có thể làm cho nó trở thành một phương pháp mở rộng và cuộc gọi sẽ là một đẹp hơn 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

Extensions Methods ...

... là một cách tuyệt vời để bao gồm các chức năng như nếu bạn sử dụng decorator pattern, nhưng không có sự đau đớn của việc tái cấu trúc tất cả mã của bạn hoặc sử dụng tên khác của một loại phổ biến.

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 cứ đâu trong ứng dụng của bạn.

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

>> Hello My Friend 

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

6

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

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

trình như thế này ..

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

Yeah, nó xuất hiện trên tất cả các đối tượng duy nhất, có thể gây phiền nhiễu nhưng kể từ khi tôi sử dụng này cho khá nhiều tất cả các loại dữ liệu, nó giúp để chỉ đính kèm nó một đối tượng chứ không phải là sao chép nó cho tất cả các loại dữ liệu càng tốt.

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>(); 
Các vấn đề liên quan