Noobie Делегат Основы C # - PullRequest
       4

Noobie Делегат Основы C #

4 голосов
/ 22 февраля 2012

Я не думаю, что понимаю смысл метода делегата. Все примеры, которые я видел, делают что-то вроде этого:

class DelegateClass
{
    private List<string> ListString = new List<string>;
    delegate void DoSomethingToStringsDelegate(string s);

    public base()
    {
         ListString.Add("string"); ....
    }

    void ProcessStrings(DoSomethingToStringsDelegate dstsd)
    {
        foreach(string s in ListString)
            dstsd(s);
    }
}

class AClass
{
    ...
    void UseDelegateMethod(...)
    {
        DelegateClass ds = new DelegateClass();
        ds.ProcessStrings(new DoSomethingToStringsDelegate(PrintStrings);
    }
    void PrintStrings(string s)
    {
        System.out.Write(s);
    }
}

Я не понимаю, зачем это нужно, когда вы можете просто реализовать getListStrings () и сами итерировать строки, выполняя то, что вам нужно, как если бы это был делегат.

foreach( string s in ds.ggetListStrings() )
    System.out.Write(s);

Разум частных членов не имеет смысла, потому что я мог бы просто сделать:

global List<Strings> myListStrings = new List<Strings>();
ds.ProcessStrings(new DoSomethingToStringsDelegate(GetStrings);

void GetStrings(string s)
{
    myListStrings.Add(s);
}

... и теперь у меня есть тот же список, что и getListStrings (). ....

Может кто-нибудь объяснить, пожалуйста? Большое спасибо!

Ответы [ 5 ]

4 голосов
/ 22 февраля 2012

delegate полезен, потому что он фактически действует как заполнитель для любого метода, который принимает string в качестве параметра и возвращает void.

Если вы знакомы с C, это похоже на работу указателя функции. На его месте вы можете передать любой метод, который соответствует сигнатуре и типу возврата.

Например, скажем, я хочу реализовать метод, который сортирует группу объектов. В дополнение к списку объектов я также могу передать делегат, который указывает, как должна быть выполнена сортировка. Поскольку любой метод, соответствующий делегату, может быть передан, я могу динамически переключаться между различными методами, если я хочу, например, уменьшить или увеличить сортировку:

 delegate int comparisonDelegate(int p1, int p2);

 void SortArray(int[] array, comparisonDelegate cmp)
 {
      // determine order according to cmp
 }

 int CompareDecreasing(int p1, int p2)
 {
     if(p1 > p2) return -1;
     if(p1 < p2) return 1;
     return 0;
 }

 int CompareIncreasing(int p1, int p2)
 {
     if(p1 > p2) return 1;
     if(p1 < p2) return -1;
     return 0;
 }

Теперь я могу позвонить SortArray как:

 SortArray(array, new comparisonDelegate(compareDecreasing));
 SortArray(array, new comparisonDelegate(compareIncreasing));
3 голосов
/ 22 февраля 2012

Я не понимаю, зачем это нужно, когда вы можете просто реализовать getListStrings () и сами итерировать строки, выполняя то, что вам нужно, как если бы это был делегат.

Цель здесь - создать функцию, которая будет работать с коллекцией, но выполнять любые операции.

Это проще понять на примере - увидеть отличный пример того, как и почему это полезно,посмотрите на LINQ to Objects.

Предположим, вы хотите увидеть, сколько ваших строк длиннее 4 символов - метод Enumerable.Count имеет перегрузку, которая принимает делегата - a Func<T,bool> предикат, который можно использовать.Это позволяет вам указать любую операцию и сосчитать элементы, например:

List<string> listOfStrings = GetListOfStrings();

int countOfStringsGreaterThanFourChars = listOfStrings.Count(s => s.Length > 4);

Здесь мы передаем делегат (созданный с помощью лямбда-выражения), который дает нам наши критерии.Имея метод Count, который принимает делегата, он работает для любых критериев, поэтому нам не нужно переопределять это каждый раз, когда мы хотим другое условие.

Скажем, мы хотим увидеть, сколько строк начинаетсяс "E" мы могли бы просто использовать:

int countOfStringsStartingWithE = listOfStrings.Count(s => s.StartsWith("E"));

Опять же, нам нужно только написать код, соответствующий нашей конкретной потребности , а не дублировать весь стандартный код, которыйбыть обязательным, чтобы просмотреть нашу коллекцию и посчитать предметы ...

1 голос
/ 22 февраля 2012

Использование делегата на иллюстрации позволяет изменить реализацию метода.

Лучший пример - метод Comparer. Я не буду входить в интерфейс IComparer, но достаточно сказать, что, используя делегат, вы сможете изменить поведение метода сортировки, передав его делегату в функцию сравнения.

http://msdn.microsoft.com/en-us/library/system.collections.icomparer.aspx

0 голосов
/ 22 февраля 2012

Думайте об этом с точки зрения событий. Скажем, у вас есть класс, который выполняет некоторую обработку списка элементов, и для каждого элемента кто-то, потребляющий ваш класс, может захотеть получить уведомление о том, что элемент обработан (возможно, обновить индикатор выполнения или обновить какую-то другую часть системы). , без разницы). Давайте отложим делегатов на секунду и посмотрим, как мы можем реализовать это с помощью интерфейсов:

public class MyClassThatDoesSomething
{
   private List<string> list = new List<string>();
   public void ProcessList()
   {
      foreach(var item in list)
      {
         ProcessItem(item);
         //how do we notify someone here??
      }
   }

   private void ProcessItem(string item){}
}

Теперь скажите, что кто-то потребляет этот класс:

var mc = new MyClassThatDoesSomething();
mc.ProcessList(); //how do I know when each one has been processed?

Итак, решим эту проблему, давайте создадим интерфейс:

public interface IItemProcessed
{
   void ItemProcessed(string item);
}

Теперь мы можем реорганизовать наш оригинальный класс:

public class MyClassThatDoesSomething
{
   private List<string> list = new List<string>();
   public void ProcessList()
   {
      foreach(var item in list)
      {
         ProcessItem(item);
         //how do we notify someone here??
         if(this.Listener != null)
         {
             this.Listener.ItemProcessed(item);
         }
      }
   }

   private void ProcessItem(string item){}

   public IItemProcessed Listener {get;set;}
}

и потребитель вашего класса теперь может сделать это:

public class ProcessListener : IItemProcessed
{
   public void ItemProcessed(string item)
   {
      Console.WriteLine(item);
      //update progress bar, whatever
   }
}

var mc = new MyClassThatDoesSomething();
mc.Listener = new ProcessListener();
mc.ProcessList(); 

Теперь, когда вы понимаете это, вы можете думать о делегатах как о мини-интерфейсах, а затем можете изменить свой исходный класс на следующий:

public class MyClassThatDoesSomething
{
   private List<string> list = new List<string>();
   public void ProcessList()
   {
      foreach(var item in list)
      {
         ProcessItem(item);
         //how do we notify someone here??
         if(this.Callback != null)
         {
             this.Callback(item);
         }
      }
   }

   private void ProcessItem(string item){}

   public Action<string> Callback {get;set;}
}

и потребитель:

var mc = new MyClassThatDoesSomething();
mc.Listener = s =>
{
   Console.WriteLine(s);
   //update progress bar, whatever
}
mc.ProcessList(); 

Подводя итог, вы можете думать о делегатах как о способе обеспечить посторонним простую «зацепку» в вашем коде, чтобы позволить им предоставлять небольшие кусочки логики (например, Linq и фильтрацию коллекции) или для обратных вызовов / событий, подобных I продемонстрировал выше.

0 голосов
/ 22 февраля 2012

С одной стороны, это позволяет вам вводить различные варианты поведения с одной и той же сигнатурой метода. В одном случае вы можете просто добавить в свой список. В другом случае вы можете добавить в список и записать в файл журнала, или что-то еще, что вы можете сделать в DoSomethingToStringsDelegate.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...