Лекция 16. Методы расширения

Методы расширения (extension methods) позволяют добавлять новые методы в уже существующие типы без создания нового производного класса. Эта функциональность бывает особенно полезна, когда нам хочется добавить в некоторый тип новый метод, но сам тип (класс или структуру) мы изменить не можем.

Например, нам надо добавить для типа string новый метод:

class Program

{

static void Main(string[] args)

{

   string s = "Привет мир";

   char c = 'и';

   int i = s.WordCount(c);

   Console.WriteLine(i);

 

   Console.ReadLine();

}

}

 

public static class StringExtension

{

public static int WordCount(this string str, char c)

{

   int counter = 0;

   for (int i = 0; i<str.Length; i++)

   {

       if (str[i] == c)

           counter++;

   }

   return counter;

}

}

Для того, чтобы создать метод расширения, вначале надо создать статический класс, который и будет содержать этот метод. В данном случае это класс StringExtension. Затем объявляем статический метод. Суть нашего метода расширения - подсчет количества определенных символов в строке.

Собственно метод расширения - это обычный статический метод, который в качестве первого параметра всегда принимает такую конструкцию: this имя_типа название_параметра, то есть в нашем случае this string str. Так как наш метод будет относиться к типу string, то мы и используем данный тип.

Затем у всех строк мы можем вызвать данный метод: int i = s.WordCount(c);. Причем нам уже не надо указывать первый параметр. Значения для остальных параметров передаются в обычном порядке.

Применение методов расширения очень удобно, но при этом надо помнить, что метод расширения никогда не будет вызван, если он имеет ту же сигнатуру, что и метод, изначально определенный в типе.

Также следует учитывать, что методы расширения действуют на уровне пространства имен. То есть, если добавить в проект другое пространство имен, то метод не будет применяться к строкам, и в этом случае надо будет подключить пространство имен метода через директиву using.

Лекция 17. Локальные функции

Локальные функции представляют функции, определенные внутри других методов. Локальные функции доступны начиная с версии C# 7.0 (Visual Studio 2017).

Определим и используем локальную функцию:

class Program

{

static void Main(string[] args)

{

   var result = GetResult(new int[] { -3, -2, -1, 0, 1, 2, 3 });

   Console.WriteLine(result); // 6

   Console.Read();

}

 

static int GetResult(int[] numbers)

{

                          int limit = 0;

   // локальная функция

   bool IsMoreThan(int number)

   {

       return number > limit;

   }

 

   int result = 0;

   for(int i=0; i < numbers.Length; i++)

   {

       if (IsMoreThan(numbers[i]))

       {

           result += numbers[i];

       }

   }

 

   return result;

}

}

Здесь в методе GetResult определена локальная функция IsMoreThan(), которая может быть вызвана только внутри этого метода. Локальная функция задает еще одну область видимости, где мы можем определять переменные и выполнять над ними действия. В то же время ей доступны все переменные, которые определены в том же методе.

При использовании локальных функций следует помнить, что они не могут иметь модификаторов доступа (public, private, protected). Нельзя определить в одном методе несколько локальных функций с одним и тем же именем, даже если у них будет разный список параметров. Кроме того, не имеет значения, определены локальные функции до своего вызова или после.

 

Лекция 18. Пространства имен, псевдонимы и статический импорт

Пространства имен

Все определяемые классы не существуют сами по себе, а, как правило, заключаются в специальные контейнеры - пространства имен. Создаваемый по умолчанию класс Program уже находится в пространстве имен, которое обычно совпадает с названием проекта:

namespace HelloApp

class Program 

{

   static void Main(string[] args)

   {

                          }

           }

}

Пространство имен определяется с помощью ключевого слова namespace, после которого идет название. Так в данном случае полное название класса Program будет HelloApp.Program.

Класс Program видит все классы, которые объявлены в том же пространстве имен:

namespace HelloApp

class Program 

{

   static void Main(string[] args)

   {

                                           Account account = new Account(4);

                          }

           }

           class Account

{

   public int Id { get; private set;} // номер счета

   public Account(int _id)

   {

       Id = _id;

   }

           }

}

Но чтобы задействовать классы из других пространств имен, эти пространства надо подключить с помощью директивы using:

using System;

namespace HelloApp

class Program 

{

   static void Main(string[] args)

   {

                                          Console.WriteLine("hello");

                          }

           }

}

Здесь подключается пространство имен System, в котором определен класс Console. Иначе нам бы пришлось писать полный путь к классу:

static void Main(string[] args)

{

           System.Console.WriteLine("hello");

}

Пространства имен могут быть определены внутри других пространств:

using HelloApp.AccountSpace;

namespace HelloApp

class Program 

{

   static void Main(string[] args)

   {

       Account account = new Account(4);

   }

}

 

namespace AccountSpace

{

   class Account

   {

       public int Id { get; private set;}

       public Account(int _id)

       {

           Id = _id;

       }

   }

}

}

В этом случае для подключения пространства указывается его полный путь с учетом внешних пространств имен: using HelloApp.AccountSpace;

Псевдонимы

Для различных классов мы можем использовать псевдонимы. Затем в программе вместо названия класса используется его псевдоним. Например, для вывода строки на экран применяется метод Console.WriteLine(). Но теперь зададим для класса Console псевдоним:

using printer = System.Console;

class Program

{

static void Main(string[] args)

{

   printer.WriteLine("Hello from C#");

   printer.Read();

}

}

С помощью выражения using printer = System.Console указываем, что псевдонимом для класса System.Console будет имя printer. Это выражение не имеет ничего общего с подключением пространств имен в начале файла, хотя и использует оператор using. При этом используется полное имя класса с учетом пространства имен, в котором класс определен. И далее, чтобы вывести строку, применяется выражение printer.WriteLine("Hello from C#").

И еще пример. Определим класс и для него псевдоним:

using Person = HelloApp.User;

using Printer = System.Console;

namespace HelloApp

{

  class Program

{

   static void Main(string[] args)

   {

       Person person = new Person();

       person.name = "Tom";

       Printer.WriteLine(person.name);

       Printer.Read();

   }

}

 

class User

{

   public string name;

}

}

Класс называется User, но в программе для него используется псевдоним Person.

Начиная с версии C# 6.0 (Visual Studio 2015) в язык была добавлена возможность импорта функциональности классов. Например, опять же возьмем класс Console и применим новую функциональность:

using static System.Console;

namespace HelloApp

{

class Program

{

   static void Main(string[] args)

   {

       WriteLine("Hello from C# 6.0");

       Read();

   }

}

}

Выражение using static подключает в программу все статические методы и свойства, а также константы. И после этого мы можем не указывать название класса при вызове метода.

Подобным образом можно определять свои классы и импортировать их:

using static System.Console;

using static System.Math;

using static HelloApp.Geometry;

namespace HelloApp

{

class Program

{

   static void Main(string[] args)

   {

       double radius = 50;

       double result = GetArea(radius); //Geometry.GetArea

       WriteLine(result); //Console.WriteLine

       Read(); // Console.Read

   }

}

 

class Geometry

{

   public static double GetArea(double radius)

   {

       return PI * radius * radius; // Math.PI   } } }


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: