Небольшой пример про делегаты
Иногда может сложиться такая ситуация, что вы точно не знаете имя метода, который надо передать в стороннюю функцию, но она должна быть унифицирована. К тому же делегаты можно складывать.
Типичный пример с сортировками.
namespace ConsoleApplication1
{
public delegate void TypeSort(ref int[] arr);
static public class SortMethod{
static public void Inc(ref int[] arr)
{
int j, k;
for (int i = 0; i < arr.Length - 1; i++)
{
j = 0;
do
{
if (arr[j] > arr[j + 1])
{
k = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = k;
}
j++;
}
while (j < arr.Length - 1);
}
}
static public void Dec(ref int[] arr)
{
int j, k;
for (int i = 0; i < arr.Length - 1; i++)
{
j = 0;
do
{
if (arr[j] < arr[j + 1])
{
k = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = k;
}
j++;
}
while (j < arr.Length - 1);
}
}
static public void Write(ref int[] arr)
{
Console.Write("Массив: ");
foreach (int i in arr)
Console.Write("{0}\t", i);
Console.WriteLine();
}
}
public class Program
{
static void Main(string[] args)
{
int[] myArr = new int[6] { 2, -4, 10, 5, -6, 9 };
TypeSort typesort = new TypeSort(SortMethod.Write);
typesort += SortMethod.Inc;
typesort += SortMethod.Write;
typesort += SortMethod.Dec;
typesort += SortMethod.Write;
typesort(ref myArr);
Console.Read();
}
}
}
В данном случае методы выполняются в Main, но практика использования делегатов в том, что они передаются в другие функции, которые не должны жестко кодировать используемый метод.
Небольшой пример про интерфейсы
Другой дело с интерфейсами, они нужны для четкого описания того, что есть в классе. К примеру, вы делаете приложение, которое выполняет подключение к БД. Вам надо сделать подключение в трем типам СУБД по выбору: MySQL, SQL SERVER и Oracle. Вы могли бы делать для каждого свой класс и таскать их, но проще таскать интерфейс, не зная реализации класса.
public interface IDBConnect
{
public bool Query(String query);
}
public class MSSQL : IDBConnect
{
public bool Query(string query)
{
Console.WriteLine("Запрос к MSSQL");
return true;
}
}
public class MySQL : IDBConnect
{
public bool Query(string query)
{
Console.WriteLine("Запрос к MySQL");
return true;
}
}
public class Oracle : IDBConnect
{
public bool Query(string query)
{
Console.WriteLine("Запрос к Oracle");
return true;
}
}
Теперь код, который использует подключения, может не думать о внутренней реализации этих подключений и выполнять их через интерфейс.
public class useConnect
{
IDBConnect connect;
useConnect(IDBConnect con)
{
connect = con;
}
public void useQuery()
{
connect.Query("Запрос");
}
}
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("Выберите базу:");
String DBase = Console.ReadLine();
UseConnect connect;
switch(DBase){
case "MSSQL":
connect = new UseConnect(new MSSQL());
break;
case "MySQL":
connect = new UseConnect(new MySQL());
break;
default:
connect = new UseConnect(new Oracle());
break;
}
/* теперь нашему connect все равно, что там за база на самом деле */
connect.useQuery();
Console.Read();
}
}
К тому же стоит заметить, что очень легко добавить новую базу (или абсолютно полностью переписать старую), унаследовав интерфейс и не меняя весь остальной код. Еще тут выполняется полиморфизм, вы всегда знаете, какие методы может иметь тот или иной класс, глядя на его интерфейс. Это также позволяет Вам писать свои классы на этом интерфейсе. Часто используемый пример - это встроенные IQueryable и IEnumerable, унаследовавшись от которых, ваши собственные классы могут реализовать правильное поведение "Как массив" для обращений по индексу myClass[1] и "Как перечисление" для foreach(var in myClass) { ... }.
Ну и поскольку тут поднималась тема про книги, то вот хороший список:
Классические книги по C#/.NET
UPD
В дополнение, часто используются делегаты для подписывания (и отписывания с помощью операции -=) на события.
public delegate void EventComplete();
class First{
public EventComplete Complete;
public void Do(){
Thread.Sleep(2000);
Complete();
}
}
class Second
{
public void Ok()
{
Console.WriteLine("Класс First выполнил действие");
}
}
public class Program
{
static void Main(string[] args)
{
First obj = new First();
obj.Complete += new EventComplete( new Second().Ok );
obj.Complete += new EventComplete( new Second().Ok );
obj.Do();
}
}
Это только то, что вспомнил сразу, там еще есть много ситуаций, где удобны классы и интерфейсы для применения.