борется в понимании терминов в мире делегатов - PullRequest
0 голосов
/ 31 мая 2019

Я новичок в C #, меня очень смущают такие термины, как 'listener', 'caller', 'callback', 'EventHandler', скажем, у нас есть следующий код ниже:

public class Car 
{
    public delegate void CarEngineHandler();
    public CarEngineHandler listOfHandlers;
    public void Accelerate(int delta)
    {
       if (delta > 80) 
          listOfHandlers();    // not checking null for simplicity 
    }
}

class Program
{
    static void Main(string[] args)
    {
         Car myCar = new Car(); 
         myCar.listOfHandlers = new Car.CarEngineHandler(CallWhenExploded);
         myCar.Accelerate(120);
    }

    static void CallWhenExploded() 
    {
       Console.WriteLine("Sorry, this car is dead..."); 
    }
}

так в этом сценарии:

  1. Кто звонит?

  2. Кто слушатель?что слушать?

  3. Кто обратный вызов?

  4. Кто такой EventHandler?

и мой ответ:

  1. Вызывающая сторона myCar
  2. не уверен
  3. Обратный вызов CallWhenExploded() статическая функция
  4. EventHandler это listOfHandlers

я прав?Я действительно не знаю, кто слушатель, и что я слушаю.

Ответы [ 2 ]

3 голосов
/ 31 мая 2019

Надеюсь, вы понимаете, что переменная типа string похожа на контейнер, содержащий строку символов, и вы можете посмотреть на них по отдельности, передать их как коллекцию и т. Д. Это довольно легко визуализировать, поскольку эта переменная контейнер, в котором хранятся данные, потому что мы постоянно храним данные в реальном мире; кусочки бумаги в коробке / файле и т. д.

Делегаты подобны переменным для методов - и это гораздо сложнее понять, что мы можем передать метод, как если бы он был просто как данные, и мы можем заставить компьютер запустить метод .. но это то, что делегат. Когда вы объявляете делегата, это как когда вы объявляете свой собственный класс:

delegate void SomeMethod(); //specify a delegate

class Person{               //specify a class
  string FirstName;
  string LastName;
}

Точно так же, как когда вы создаете класс, вы даете себе возможность создать экземпляр этого класса, когда вы объявляете делегата, вы даете себе возможность создать экземпляр этого делегата. Ваш экземпляр класса ссылается на данные, например, здесь имя и фамилия человека. Экземпляр делегата ссылается на метод, а не на данные. Вы можете создать один экземпляр класса, который ссылается на «Джона» и «Смита». Вы можете создать экземпляр делегата, который ссылается на Method1 (). Вы можете создать другой экземпляр класса, который ссылается на «Билл», «Джонс». Вы можете создать другой экземпляр делегата, который ссылается на Method2 ().

Вы можете связать любой метод с вашим экземпляром делегата, если метод имеет сигнатуру, равную делегату. Этот делегат выше примет ссылку на любой метод, который не принимает параметров и возвращает void. Если у вас есть один или несколько таких методов, вы можете присоединить их к экземпляру делегата, передать экземпляр делегата как переменную, и вещь, которой вы передали делегат, может вызывать методы без необходимости знать как называется метод или что-то в этом роде.

Зачем нам это делать? Одно из основных применений делегатов - обработка событий. Microsoft создала элементы управления пользовательским интерфейсом, которые способны что-то делать - кнопки, на которые вы можете нажимать. Вы захотите, чтобы ваша кнопка что-то делала при нажатии, но все в мире захотят, чтобы при нажатии ее кнопка делала что-то другое, поэтому Microsoft не может написать код для этого. Однако они могут сказать, что сделают кнопку, которая принимает делегата (метод, переданный как переменную), и кнопка обещает вызвать метод при нажатии. Вы предоставляете кнопке код, который делает то, что вы хотите, как делегат. Ваш метод должен иметь определенную подпись (аргументы), потому что кнопка хочет передать вашему методу некоторые данные, которые могут быть вам полезны; возможно, местоположение мыши при появлении часов или число нажатий на них. Компоненты пользовательского интерфейса имеют сотни различных видов событий, все они работают на делегатах

Еще один хороший пример делегатов - в старом стиле асинхронного программирования, когда у нас были пары методов Begin / End. Вызов Begin обычно запускал бы новый поток, делая что-то, и мы должны были бы предоставить метод (наш метод) для если метод Microsoft Begin завершит выполнение чего-либо, он вызовет наш метод, чтобы сообщить нам об этом. Обычно тогда наш код вызывает End, передавая некоторую ссылку, которую дал наш метод, и мы получаем результат. Например, отправка запроса на сервер может занять некоторое время, поэтому мы начнем его, перейдем к другим действиям, и когда ответ будет готов, наш делегат получит уведомление о вызове и обработает результат

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

Сам делегат больше похож на коллекцию / массив - вы можете прикрепить несколькометоды к нему и при вызове делегата все они будут работать, но не в каком-либо определенном порядке.В вашем примере вы присвоили ему только один, но это может быть несколько:

SomeMethod delegs = null;
delegs += new SomeMethod(MyMethod1);
delegs += new SomeMethod(MyMethod2);

Вызов этого делегата вызовет запуск MyMethod1 и MyMethod2, возможно, в 2,1 порядке


События также являются делегатами, но это немного особый случай, о котором мы говорили выше с помощью обработчика нажатия кнопки.Когда делегат указан с ключевым словом события, он может быть вызван только внутри класса, который объявил переменную делегата.Элементы управления пользовательского интерфейса используют это, чтобы гарантировать, что только они могут выполнять делегат;Вы не можете получить доступ к кнопке и принудительно запустить ее обработчики часов, потому что список делегатов, который обрабатывает щелчок, объявлен как событие.Если вы хотите, чтобы кнопка программно вызывала список обработчиков событий, вы обычно должны создавать его подклассы, чтобы ваш код стал «внутри» кода кнопки

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

В стороне, потому что экземпляры делегатов представляют переменную, которая указывает на метод, т.е.они указывают на действие, ваши имена должны быть глаголом, а не существительным.Вы вызвали свой listOfHandlers, но для вашего понимания было бы более полезно вызвать экземпляр делегата после происходящего события / действия.Вариант использования, к которому вы обращались, был чрезмерным, поэтому, возможно, вам следует назвать его CarEngineOverRevving.Вы могли бы иметь другой, когда температура превышает.Если оба этих делегата имеют одинаковую подпись (вы хотите, чтобы люди, которые будут обрабатывать эти события, делали это с помощью метода без аргументов), вы можете повторно использовать один и тот же делегат для разных событий:

public void delegate CarEngineProblemHandler();
public CarEngineProblemHandler CarEngineOverRevving = null;
public CarEngineProblemHandler CarEngineOverheating = null;

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

0 голосов
/ 31 мая 2019

Вы должны быть в состоянии ответить на эти вопросы, когда поймете шаблон «вещатель / подписчик», используемый делегатами. 'broadcaster' содержит экземпляр делегата и решает, когда вызывать целевые методы в своем 'списке вызовов'. Этими целевыми методами являются «подписчики», и они могут решить, когда прекратить или начать «прослушивание», вызвав «- =» или «+ =» в поле делегата вещателя.

public class Car 
{
    // This is the 'delegate type'
    // ‘Delegate type’ is what is responsible for defining the method such as its signature 
    // which include return type and parameters
    // In this ‘Delegate type’ named:'CarEngineHandler', the return type is 'void' and there are no parameters
    public delegate void CarEngineHandler();

    //this is the ‘Delegate instance’
    //‘Delegate instance’ is responsible for holding the reference to the actual methods 
    //that adheres to the delegate type. 
    //Delegate instance can be used to then ‘invoke’ that method whenever needed. 
    public CarEngineHandler listOfHandlers;


    public void Accelerate(int delta)
    {
       if (delta > 80) 
            //this is where you use the 'Delegate instance' to ‘invoke’ the methods 
            // You can also you use: listOfHandlers.Invoke(); 
            // which is same as calling 'listOfHandlers();'
            // When delegate instance is invoked, all its actions in its invocation list are executed in order
            //In this example it will first dispaly: "Sorry, this car is dead..."
            // then display: "Calling, emergency..."
          listOfHandlers();    // not checking null for simplicity 
    }
}

class Program
{
    static void Main(string[] args)
    {
            Car myCar = new Car(); 
            //This is where you add to the 'delegate instance', the 'target method's' that matches delegate signature
            //A 'delegate instance' can contain more than one action. This list of actions is called the “invocation list”.
            //You can also add multiple methods to invocation list like this: myCar.listOfHandlers += CallWhenExploded;  
            myCar.listOfHandlers = new Car.CarEngineHandler(CallWhenExploded);
            // For example you can add another target method like this:
            myCar.listOfHandlers += CallEmergencyService; 

            // you get details about the 'target methods' attached to the “invocation list” like this:
            var listOfTargets = myCar.listOfHandlers.GetInvocationList();
            Console.WriteLine(listOfTargets[0].Method.Name); 


            myCar.Accelerate(120);
    }

    static void CallWhenExploded() 
    {
       Console.WriteLine("Sorry, this car is dead..."); 
    }
    static void CallEmergencyService() 
    {
       Console.WriteLine("Calling, emergency..."); 
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...