Cũng nên nhớ rằng các phương thức mở rộng đã được thêm vào như một cách để giúp truy vấn Linq dễ đọc hơn, khi được sử dụng trong kiểu C # của chúng.
Hai ảnh hưởng này hoàn toàn tương đương, nhưng ảnh hưởng đầu tiên dễ đọc hơn nhiều (và khoảng cách về khả năng đọc tất nhiên sẽ tăng lên khi có nhiều phương pháp được xâu chuỗi hơn).
int n1 = new List<int> {1,2,3}.Where(i => i % 2 != 0).Last();
int n2 = Enumerable.Last(Enumerable.Where(new List<int> {1,2,3}, i => i % 2 != 0));
Lưu ý rằng cú pháp đủ điều kiện thậm chí phải là:
int n1 = new List<int> {1,2,3}.Where<int>(i => i % 2 != 0).Last<int>();
int n2 = Enumerable.Last<int>(Enumerable.Where<int>(new List<int> {1,2,3}, i => i % 2 != 0));
Tình cờ, các tham số kiểu của Where
và Last
không cần phải được đề cập rõ ràng vì chúng có thể được suy ra nhờ sự hiện diện của tham số đầu tiên của hai phương thức này (tham số được giới thiệu bởi từ khóathis
và làm cho chúng là phương thức mở rộng).
Điểm này rõ ràng là một lợi thế (trong số những điểm khác) của các phương thức mở rộng và bạn có thể hưởng lợi từ nó trong mọi tình huống tương tự có liên quan đến chuỗi phương thức.
Đặc biệt, đó là cách thanh lịch và thuyết phục hơn mà tôi tìm thấy để có một phương thức lớp cơ sở có thể bị xâm nhập bởi bất kỳ lớp con nào và trả về một tham chiếu được gõ mạnh cho lớp con này (với kiểu lớp con).
Ví dụ (ok, kịch bản này hoàn toàn sến sẩm): sau một đêm ngon giấc, một con vật mở mắt và kêu lên; mọi con vật đều mở mắt theo cùng một cách, ngược lại chó sủa và vịt kêu.
public abstract class Animal
{
}
public static class AnimalExtension
{
public static TAnimal OpenTheEyes<TAnimal>(this TAnimal animal) where TAnimal : Animal
{
return animal;
}
}
public class Dog : Animal
{
public void Bark() { }
}
public class Duck : Animal
{
public void Kwak() { }
}
class Program
{
static void Main(string[] args)
{
Dog Goofy = new Dog();
Duck Donald = new Duck();
Goofy.OpenTheEyes().Bark();
Donald.OpenTheEyes().Kwak();
}
}
Về mặt khái niệm OpenTheEyes
nên là một Animal
phương thức, nhưng sau đó nó sẽ trả về một thể hiện của lớp trừu tượng Animal
, không biết các phương thức của lớp con cụ thể như Bark
hoặcDuck
hoặc bất cứ điều gì. 2 dòng nhận xét là * 1 và * 2 sau đó sẽ phát sinh lỗi biên dịch.
Nhưng nhờ các phương thức mở rộng, chúng ta có thể có một loại "phương thức cơ sở biết loại lớp con mà nó được gọi".
Lưu ý rằng một phương pháp chung đơn giản có thể đã thực hiện công việc, nhưng theo một cách khó xử hơn nhiều:
public abstract class Animal
{
public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal
{
return (TAnimal)this;
}
}
Lần này, không có tham số và do đó không có suy luận kiểu trả về có thể có. Cuộc gọi không thể là gì khác hơn là:
Goofy.OpenTheEyes<Dog>().Bark();
Donald.OpenTheEyes<Duck>().Kwak();
... có thể làm nặng mã rất nhiều nếu có nhiều chuỗi liên quan hơn (đặc biệt khi biết rằng tham số kiểu sẽ luôn nằm <Dog>
trên dòng của Goofy và <Duck>
trên dòng của Donald ...)