Також пам’ятайте, що методи розширення були додані як спосіб, який допомагає запиту Linq бути більш читабельним при використанні у їх стилі C #.
Ці 2 афектації абсолютно рівнозначні, однак перший набагато читабельніший (і розрив у готовності, звичайно, збільшиться із збільшенням кількості методів, прикутих до ланцюга).
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));
Зверніть увагу, що повноцінним синтаксисом має бути навіть:
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));
Випадково, параметри типу Where
і Last
не потрібно чітко згадувати, оскільки їх можна ввести завдяки наявності першого параметра цих двох методів (параметра, який вводиться ключовим словомthis
та робить їх методами розширення).
Цей момент, очевидно, є перевагою (серед інших) методів розширення, і ви можете скористатися ним у кожному подібному сценарії, де задіяний ланцюжок методів.
Особливо, це більш елегантний і переконливий спосіб, який я виявив, що метод базового класу викликається будь-яким підкласом і повертає сильно набране посилання на цей підклас (із типом підкласу).
Приклад (добре, цей сценарій абсолютно сирний): після доброї ночі тварина відкриває очі, потім кричить; кожна тварина відкриває очі однаково, тоді як собака гавкає, а качка квакає.
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();
}
}
Концептуально OpenTheEyes
повинен бути Animal
метод, але він потім повертає екземпляр абстрактного класу Animal
, який не знає конкретних методів підкласу , як Bark
або Duck
чи будь інший . Потім два рядки, коментовані як * 1 та * 2, спричинять помилку компіляції.
Але завдяки методам розширення ми можемо мати свого роду "базовий метод, який знає тип підкласу, за яким він називається".
Зверніть увагу, що простий загальний метод міг би виконати цю роботу, але набагато незручнішим чином:
public abstract class Animal
{
public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal
{
return (TAnimal)this;
}
}
Цього разу жодного параметра і, отже, жодного можливого виводу типу повернення. Дзвінок може бути не чим іншим, як:
Goofy.OpenTheEyes<Dog>().Bark();
Donald.OpenTheEyes<Duck>().Kwak();
... що може значно зважити код, якщо задіяно більше ланцюжків (особливо знаючи, що параметр type завжди буде <Dog>
в рядку Гуфі та в рядку <Duck>
Дональда ...)