
Всё больше наших коллег на практике предпочитают избегать применения операторов if. Эти условия, по их мнению, усложняют и прибавляют багов в наши приложения.
Но условия лежат в основе программирования, и мы не можем полностью избавиться от операторов if — мы можем лишь сократить их использование.
Что такое словарь?
Словарь — это структура данных, предназначенная для хранения группы объектов. Он может использоваться для маппинга, кэша в оперативной памяти, таблиц и т.д. Объекты хранятся в нём как коллекция пар ключ/значение, что очень удобно и характерно для разных объектно-ориентированных языков программирования. Таким же образом — в виде пар ключ/значение — могут быть заданы делегаты.
Что такое делегат?
«Делегат — это объект, который ссылается на метод. Или даже можно сказать, что это переменная ссылочного типа, которая содержит ссылку на методы. Делегаты в C# схожи с указателем на функцию в C/C++. Он помогает определить, какой метод должен вызываться при срабатывании события».
Есть два типа делегатов, которые нужны для наших примеров: Actionи Func. Action используется для методов void, а Func — для методов возвращаемого типа return.
Например:
static void Main(string[] args) { Dictionary<string, Action> dict = new Dictionary<string, Action>(); dict.Add("foo", bar); dict["foo"].Invoke(); Console.WriteLine("World"); Console.ReadLine(); } static void bar() { Console.WriteLine("Hello"); }
Здесь определяется словарь с типом <string, Action> и к нему добавляется элемент, а затем выполняется метод для вызова dict[“foo”]. Можем использовать dict[“foo”]() как альтернативу dict[“foo”].Invoke().
Результат:

Какой полезный метод, правда?:)
Пример
Предположим, у нас есть модуль генерации отчётов, который создаёт периодические отчёты: ежедневные, еженедельные, ежемесячные, ежегодные и т.д. Причём они не содержат параметрического или возвращаемого типа.
Сначала он выглядит вот так:
using System; using System.Collections.Generic; namespace DictionaryTraining { public class Program { static void Main(string[] args) { Reporter reporter = new Reporter(); ReportType reportType = ReportType.Monthly; PrepareReport(reportType); Console.ReadLine(); } private static void PrepareReport(ReportType reportType) { Reporter reporter = new Reporter(); if (reportType == ReportType.Daily) { reporter.GetDailyReport(); } else if (reportType == ReportType.Weekly) { reporter.GetWeeklyReport(); } else if (reportType == ReportType.Monthly) { reporter.GetMonthlyReport(); } else if (reportType == ReportType.Annual) { reporter.GetAnnualReport(); } } } public class Reporter { public void GetDailyReport() { Console.WriteLine("Daily report is preparing..."); } public void GetWeeklyReport() { Console.WriteLine("Weekly report is preparing..."); } public void GetMonthlyReport() { Console.WriteLine("Monthly report is preparing..."); } public void GetAnnualReport() { Console.WriteLine("Annual report is preparing..."); } } public enum ReportType { Daily, Weekly, Monthly, Annual } }
Теперь у нас есть класс Reporter с разными методами для подготовки отчётов.
Для вызова определённого метода в соответствии с типом каждого отчёта используется метод PrepareReport. Для этого будет задействовано множество операторов if-else.
Ну а мы попробуем вместо них использовать словарь и делегаты:
using System; using System.Collections.Generic; namespace DictionaryTraining { public class Program { static Dictionary<ReportType, Action> dictReports = new Dictionary<ReportType, Action>(); static void Main(string[] args) { Reporter reporter = new Reporter(); dictReports.Add(ReportType.Daily, new Action(reporter.GetDailyReport)); dictReports.Add(ReportType.Weekly, new Action(reporter.GetWeeklyReport)); dictReports.Add(ReportType.Monthly, new Action(reporter.GetMonthlyReport)); dictReports.Add(ReportType.Annual, new Action(reporter.GetAnnualReport)); dictReports[ReportType.Weekly](); Console.ReadLine(); } } public class Reporter { public void GetDailyReport() { Console.WriteLine("Daily report is preparing..."); } public void GetWeeklyReport() { Console.WriteLine("Weekly report is preparing..."); } public void GetMonthlyReport() { Console.WriteLine("Monthly report is preparing..."); } public void GetAnnualReport() { Console.WriteLine("Annual report is preparing..."); } } enum ReportType { Daily, Weekly, Monthly, Annual } }
Словарь с типом <ReportType, Action> будет использоваться в качестве делегата, а методы создания отчёта будут вызываться без необходимости проверять тип каждого отчёта.
На мой взгляд, это более читаемый и лёгкий в сопровождении код. Меньше строк — больше ясности.
Делегаты с возвращаемым типом
Если методы для подготовки отчётов имеют возвращаемый тип, должен использоваться делегат Func (но все методы должны иметь те же параметрические и возвращаемый типы).
Вот так:
using System; using System.Collections.Generic; namespace DictionaryTraining { public class Program { static Dictionary<ReportType, Func<int, string>> dictReports = new Dictionary<ReportType, Func<int, string>>(); static void Main(string[] args) { Reporter reporter = new Reporter(); dictReports.Add(ReportType.Daily, new Func<int, string>(reporter.GetDailyReport)); dictReports.Add(ReportType.Weekly, new Func<int, string>(reporter.GetWeeklyReport)); dictReports.Add(ReportType.Monthly, new Func<int, string>(reporter.GetMonthlyReport)); dictReports.Add(ReportType.Annual, new Func<int, string>(reporter.GetAnnualReport)); dictReports[ReportType.Daily](60); Console.ReadLine(); } } public class Reporter { public string GetDailyReport(int dayOfYear) { Console.WriteLine("Daily report is preparing..."); return "report of day: " + dayOfYear; } public string GetWeeklyReport(int weekOfYear) { Console.WriteLine("Weekly report is preparing..."); return "report of week: " + weekOfYear; } public string GetMonthlyReport(int monthOfYear) { Console.WriteLine("Monthly report is preparing..."); return "report of month: " + monthOfYear; } public string GetAnnualReport(int year) { Console.WriteLine("Annual report is preparing..."); return "report of year: " + year; } } enum ReportType { Daily, Weekly, Monthly, Annual } }
И вот результат:

А сколько ещё есть вариантов применения словаря с точки зрения роста показателей производительности!
Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming