438 Stimmen

Wann und warum sollte man Delegierte einsetzen?

Ich bin relativ neu in C#, und ich frage mich wann man Delegierte richtig einsetzt . Sie werden häufig bei der Erklärung von Ereignissen verwendet, aber wann sollte ich sie in meinem eigenen Code verwenden und Warum sind sie nützlich? warum nicht etwas anderes verwenden?

Ich frage mich auch wenn ich Delegierte einsetzen muss und keine andere Möglichkeit habe .

Vielen Dank für die Hilfe!

EDIT: Ich glaube, ich habe eine notwendiger Einsatz von Delegierten aquí

28voto

Dave Punkte 7885

Ich habe gerade meinen Kopf um diese, und so werde ich ein Beispiel zu teilen, wie Sie bereits Beschreibungen, aber im Moment ein Vorteil sehe ich ist, um die Circular Reference Stil Warnungen, wo man nicht haben kann 2 Projekte verweisen einander zu umgehen.

Angenommen, eine Anwendung lädt eine XML-Datei herunter und speichert sie in einer Datenbank.

Ich habe hier 2 Projekte, die meine Lösung aufbauen: FTP und eine SaveDatabase.

Unsere Anwendung beginnt also mit der Suche nach Downloads und dem Herunterladen der Datei(en) und ruft dann das SaveDatabase-Projekt auf.

Nun muss unsere Anwendung die FTP-Site benachrichtigen, wenn eine Datei in der Datenbank gespeichert wird, indem sie eine Datei mit Metadaten hochlädt (ignorieren Sie, warum, es ist eine Anfrage vom Eigentümer der FTP-Site). Die Frage ist, zu welchem Zeitpunkt und wie? Wir brauchen eine neue Methode namens NotifyFtpComplete(), aber in welchem unserer Projekte soll sie gespeichert werden - FTP oder SaveDatabase? Logischerweise sollte der Code in unserem FTP-Projekt gespeichert werden. Das würde aber bedeuten, dass NotifyFtpComplete ausgelöst werden muss, oder dass es warten muss, bis die Speicherung abgeschlossen ist, und dann die Datenbank abfragen muss, um sicherzustellen, dass die Daten dort vorhanden sind. Was wir tun müssen, ist unserem SaveDatabase-Projekt zu sagen, dass es die Methode NotifyFtpComplete() direkt aufrufen soll, aber das können wir nicht; wir würden eine zirkuläre Referenz erhalten und NotifyFtpComplete() ist eine private Methode. Wie schade, das hätte funktioniert. Nun, es kann.

Im Code unserer Anwendung hätten wir Parameter zwischen den Methoden übergeben, aber was wäre, wenn einer dieser Parameter die Methode NotifyFtpComplete wäre? Ja, wir übergeben die Methode, und zwar mit dem gesamten Code darin. Das würde bedeuten, dass wir die Methode an jedem beliebigen Punkt und von jedem beliebigen Projekt aus ausführen könnten. Nun, genau das ist der Delegat. Das heißt, wir können die Methode NotifyFtpComplete() als Parameter an unsere Klasse SaveDatabase() übergeben. Zum Zeitpunkt des Speicherns wird dann einfach der Delegat ausgeführt.

Vielleicht hilft dieses grobe Beispiel (Pseudocode). Wir gehen auch davon aus, dass die Anwendung mit der Methode Begin() der FTP-Klasse beginnt.

class FTP
{
    public void Begin()
    {
        string filePath = DownloadFileFromFtpAndReturnPathName();

        SaveDatabase sd = new SaveDatabase();
        sd.Begin(filePath, NotifyFtpComplete());
    }

    private void NotifyFtpComplete()
    {
        //Code to send file to FTP site
    }
}

class SaveDatabase
{
    private void Begin(string filePath, delegateType NotifyJobComplete())
    {
        SaveToTheDatabase(filePath);

        /* InvokeTheDelegate - 
         * here we can execute the NotifyJobComplete
         * method at our preferred moment in the application,
         * despite the method being private and belonging
         * to a different class.
         */
        NotifyJobComplete.Invoke();
    }
}

So, nachdem das erklärt ist, können wir es jetzt mit dieser Konsolenanwendung in C# in die Praxis umsetzen

using System;

namespace ConsoleApplication1
{
    /* I've made this class private to demonstrate that 
    * the SaveToDatabase cannot have any knowledge of this Program class.
    */
    class Program
    {
        static void Main(string[] args)
        {
            //Note, this NotifyDelegate type is defined in the SaveToDatabase project
            NotifyDelegate nofityDelegate = new NotifyDelegate(NotifyIfComplete);

            SaveToDatabase sd = new SaveToDatabase();            
            sd.Start(nofityDelegate);
            Console.ReadKey();
        }

        /* this is the method which will be delegated -
         * the only thing it has in common with the NofityDelegate
         * is that it takes 0 parameters and that it returns void.
         * However, it is these 2 which are essential.
         * It is really important to notice that it writes
         * a variable which, due to no constructor,
         * has not yet been called (so _notice is not initialized yet).
         */ 
    private static void NotifyIfComplete()
    {
        Console.WriteLine(_notice);
    }

    private static string _notice = "Notified";
    }

    public class SaveToDatabase
    {
        public void Start(NotifyDelegate nd)
        {
            /* I shouldn't write to the console from here, 
             * just for demonstration purposes
             */
            Console.WriteLine("SaveToDatabase Complete");
            Console.WriteLine(" ");
            nd.Invoke();
        }
    }
    public delegate void NotifyDelegate();
}

Ich schlage vor, dass Sie den Code Schritt für Schritt durchgehen und sehen, wann _notice aufgerufen wird und wann die Methode (Delegat) aufgerufen wird, da dies, so hoffe ich, die Dinge sehr klar machen wird.

Schließlich können wir es jedoch nützlicher machen, indem wir den Delegatentyp so ändern, dass er einen Parameter enthält.

using System.Text;

namespace ConsoleApplication1
{
    /* I've made this class private to demonstrate that the SaveToDatabase
     * cannot have any knowledge of this Program class.
     */
    class Program
    {
        static void Main(string[] args)
        {
            SaveToDatabase sd = new SaveToDatabase();
            /* Please note, that although NotifyIfComplete()
         * takes a string parameter, we do not declare it,
         * all we want to do is tell C# where the method is
         * so it can be referenced later,
         * we will pass the parameter later.
         */
            var notifyDelegateWithMessage = new NotifyDelegateWithMessage(NotifyIfComplete);

            sd.Start(notifyDelegateWithMessage );

            Console.ReadKey();
        }

        private static void NotifyIfComplete(string message)
        {
            Console.WriteLine(message);
        }
    }

    public class SaveToDatabase
    {
        public void Start(NotifyDelegateWithMessage nd)
        {
                        /* To simulate a saving fail or success, I'm just going
         * to check the current time (well, the seconds) and
         * store the value as variable.
         */
            string message = string.Empty;
            if (DateTime.Now.Second > 30)
                message = "Saved";
            else
                message = "Failed";

            //It is at this point we pass the parameter to our method.
            nd.Invoke(message);
        }
    }

    public delegate void NotifyDelegateWithMessage(string message);
}

12voto

Mark Seemann Punkte 216836

Ich betrachte Delegierte als Anonyme Schnittstellen . In vielen Fällen können Sie sie verwenden, wenn Sie eine Schnittstelle mit einer einzigen Methode benötigen, aber den Overhead der Definition dieser Schnittstelle nicht wollen.

4voto

Pankaj Punkte 4249

Ein Delegat ist eine einfache Klasse, die verwendet wird, um auf Methoden mit einer bestimmten Signatur zu verweisen, wodurch sie im Wesentlichen zu einem typsicheren Funktionszeiger wird. Der Zweck eines Delegaten ist es, einen Rückruf zu einer anderen Methode (oder Methoden) zu erleichtern, nachdem eine Methode auf strukturierte Weise abgeschlossen wurde.

Es wäre zwar möglich, einen umfangreichen Code zu erstellen, um diese Funktion auszuführen, aber das ist nicht nötig. Sie können einen Delegaten verwenden.

Das Anlegen eines Delegierten ist einfach zu bewerkstelligen. Kennzeichnen Sie die Klasse als Delegierten mit dem Schlüsselwort "delegate". Geben Sie dann die Signatur des Typs an.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X