Failed to Understand the Use of Delegates in Real

2019-05-06 15:54发布

问题:

I can't understand the proper use of delegates in .NET world. What can't be solved with Delegates? I want to know what scenario/situation is ideal or candidate for delegate usage.

I know LINQ and Lambda expressions all use Delegates behind the scenes. I know how to create and consume it but what I have failed to understand is WHY I should create and use them?

Any real world example or experience sharing would be highly appreciated.

Update:

I have created following classes

using System;
using System.Collections.Generic;
using System.Linq;

namespace Basics
{
public class Program
{
    static void Main()
    {
        Flight.FlightTakeOffDelegate flightDelegate;

        var flights = new List<Flight>
            {
                new Flight {Number = "FL001", DepartureTime = DateTime.Now, TotalCrew = 15},
                new Flight {Number = "FL002", DepartureTime = DateTime.Now.AddHours(1), TotalCrew = 15},
                new Flight {Number = "FL003", DepartureTime = DateTime.Now.AddHours(2), TotalCrew = 15},                    
            };

        var tower = new FlightTower(flights);

        // Flight 002 asking to Take off
        var flightAskingToTakeOff = flights.FirstOrDefault(x => x.Number == "FL002");
        if (flightAskingToTakeOff != null)
        {
            Console.WriteLine(string.Format("Flight {0} \t: Okay to take off?", flightAskingToTakeOff.Number));
            flightDelegate = tower.CanTakeOff;
            flightAskingToTakeOff.CanTakeOff = flightDelegate.Invoke(flightAskingToTakeOff);
            Console.WriteLine(string.Format("Flight Tower \t: {0}", flightAskingToTakeOff.CanTakeOff));
        }

        // Flight 001 asking to Take off
        flightAskingToTakeOff = flights.FirstOrDefault(x => x.Number == "FL001");
        if (flightAskingToTakeOff != null)
        {
            Console.WriteLine(string.Format("Flight {0} \t: Okay to take off?", flightAskingToTakeOff.Number));
            flightDelegate = tower.CanTakeOff;
            flightAskingToTakeOff.CanTakeOff = flightDelegate.Invoke(flightAskingToTakeOff);
            Console.WriteLine(string.Format("Flight Tower \t: {0}", flightAskingToTakeOff.CanTakeOff));
        }

        Console.ReadKey();
    }
}

public class FlightTower
{
    private readonly List<Flight> _schedule;

    public FlightTower(List<Flight> schedule)
    {
        _schedule = schedule;
    }


    public bool CanTakeOff(Flight flight)
    {            
        var arrivingFlights = _schedule.Where(x => x.ArrivalTime == DateTime.Now);

        if (!arrivingFlights.Any())
        {

            var flightInQueue = _schedule.FirstOrDefault(x => x.DepartureTime == _schedule.Min(c=> c.DepartureTime));
            if (flightInQueue != null && flightInQueue.Number == flight.Number)
            {                    
                return true;
            }
        }

        return false;
    }
}


public class Flight
{
    public delegate bool FlightTakeOffDelegate(Flight flight);

    public string Number { get; set; }
    public DateTime DepartureTime { get; set; }
    public DateTime ArrivalTime { get; set; }
    public int TotalCrew { get; set; }
    public bool CanTakeOff { get; set; }
}

}

Can anyone please have a look to see how can delegates be used in such scenario??

回答1:

I have one artificial but clear example for you.

Suppose you have a set of messages.

public class Message  
{
    public string Tag {get;set;}
    public byte[] RawData{ get;set;}
}

you get them from the queue.

You want to parse them.

public class Parser 
{
    private Dictionary<string, Func<Message, string>> _handlers = 
                               new Dictionary<string, Func<Message, string>>
    {
        {"Tag1", (message) => {here are parse rules}},
        {"Tag2", (message) => {here are parse rules2}},
    }

    public string Handle(Message message)
    {
        var handler = _handlers[message.Tag];
        return handler(message);
    }
}

So as you see you can treat any delegate as a normal object. You can store a collection, you can pass them to other method and so on.



回答2:

Delegates don't allow you to perform tasks that you can't already perform, but they allow you to achieve the same outcome with much cleaner and more modular code. The concept is very similar to that behind generics/interfaces, or implementations of abstract classes, but it works for actions and functions rather than objects and properties.

So let's say you have a class the controls airplanes in an airport (call it FlightTower), and a number of different planes. Each plane knows about all itself - when it is supposed to leave, whether everyone is on board - but it doesn't know about the other planes, or whether the runway is clear, or anything else.

The non-delegate approach is to give each plane access to the FlightTower to figure out when to take off. It can look through a list of planes that the FlightTower knows about, find out what they are doing, and even coordinate with other planes. Imagine each plane had a computer which connects to the FlightTower system to check what's going on; and each pilot needs to know how to use that system and figure out when it's safe to go.

The delegate approach would be for the FlightTower to give the plane a method to check whether to take off. When the plane arrives at the airport, the FlightTower gives them a few radio commands - they can ask 'okay to take off' and the FlightTower will give them an answer. The plane doesn't need to do anything thinking of its own.

The cool thing about the delegate approach is that the FlightTower can do whatever it likes when the plane asks the question (assuming it gives the correct answer). It can figure out an answer itself, it can send the query off to some scheduling system, or anything else. This is where the core of the delegation concept plays out - the plane 'delegates' the process to the FlightTower.



回答3:

GUI code uses delegates to handle events, such as button clicks, window moves. Using the delegate allows you do have a function called whenever the event occurs. An example would be linking a function that saves data to a "Save" button on the interface. When the button gets clicked it is set up to execute the function that saves data. It's useful in GUI programming because your whole program could be waiting for the user to do something and you have no way of knowing what they will do first. Using delegates allows the functionality of your program to be connected to the UI in such a way that the user can do things in any way they want.

Source : StackExchange

Example : CodeProject: 6 important uses of Delegates and Events



回答4:

A delegate is a lot like a function pointer. It is a type that matches a method signature. Instances of the delegate can be bound to methods with that signature. This allows you to pass references to methods around, even into objects which don't have visibility of the actual method.

A real world scenario where this is used is when starting a new thread. The ThreadPool class has a static method to queue a new thread. But you need to pass it a method to call from the new thread. To do this it takes a delegate parameter:

public static bool QueueUserWorkItem(WaitCallback callBack)

The WaitCallback is a delegate that matches any method with a void (object) signature:

public delegate void WaitCallback(object state)

So if you have a method:

void MyMethod(object state)
{

}

You can pass a "pointer" to this method to QueueUserWorkItem so that it can call it later (without ThreadPool needing any knowledge of your classes).

void Func()
{
    WaitCallback wc = new WaitCallback(MyMethod)
    ThreadPool.QueueUserWorkItem(wc);
}


回答5:

Event handlers are the perfect example of delegate usage.



标签: c# delegates