Diskussion Verwendung von Delegaten

Mr.Ed

Neues Mitglied
Hallo Forum,

mal eine Frage zur Definition/ Verwendung von Delegaten in c#.

Bisher habe ich Delegaten immer ungefähr so verwendet:

C#:
namespace
{  
    class klasse
    {      
        public delegate string meinDelegat(string str);
        meinDelegat handler = irgendwas;
 
        public static string irgendwas(string str)
        {
            return str;
        }
    }
}
damit bin ich bisher immer ganz gut zurecht gekommen.

neulich hat sich das ein Kollege angesehen und sich gewundert, weil er das so noch nie gesehen hat.
Ob das jetzt richtig, falsch oder einfach nur eine alternative ist konnte ich bislang nicht rausfinden.

Zwar habe ich beim Suchen im Netz, meine Variante tatsächlich so auch nicht wiederfinden können, aber mir stellt sich jetzt die Frage, warum man das scheinbar nicht so macht wie ich das tue. Ich fand das so immer ganz praktisch.

Ich hoffe ihr könnt mir da ein wenig auf die Sprünge helfen.

Liebe Grüße,
Ed
 
Zuletzt bearbeitet:

alinnert

Mitglied
Hallo Ed,

ich weiß jetzt nicht, was laut deinem Kollegen genau an der Verwendung ungewöhnlich sein soll (Ich verwende C# jetzt nicht wirklich, kenn sie aber theoretisch). Ich frage mich aber, warum du überhaupt ein Delegate erstellst. Wenn du jetzt an einer anderen Stelle handler("Hallo") oder irgendwas("Hallo") aufrufst, hätte das (meines Wissens) den gleichen Effekt. Sie haben auch den gleichen accessibility modifier (public). Auch außerhalb der Klasse dürfte es keinen Unterschied machen.

Was genau möchtest du mit dem Delegate erreichen?
 

Mr.Ed

Neues Mitglied
Hi alinnert,

ich habe Delegaten bisher verwendet um auf Funktionen in anderen Klassen zuzugreifen und habe den Handler in der klasse erstellt, weil ich dann den gleichen Handler in verschiedenen Funktionen benutzen konnte.

Mein Kollege verwendet Delegaten eher so:

C#:
class klasse 
{
    public delegate string meinDelegat(string str);
    public static string irgendwas(string str) 
    {
return str;
    }
    void wasanderes()
{
meinDelegat handler = irgendwas;
handler("hallo");
    }
}
Aber für jeden Zugriff einen neuen Handler zu deklarieren ist doch eigentlich mehr Speicher als notwendig, oder irre ich mich da? Oder gibt es noch einen weiteren Grund weshalb ich lieber jedes mal einen neuen Handler erstellen sollte, anstatt den vorhandenen zu verwenden.
 

alinnert

Mitglied
Ah, verstehe. Speicher wäre hier gar nicht mal so ein Problem, da Delegates nur Zeiger auf Funktionen sind. Die brauchen normal nicht viel Platz. Die Frage ist da eher, was aus Sicht der Architektur sinnvoller ist. Wenn du nur an wenigen Stellen Zugriff auf einen Wert brauchst, ist es übersichtlicher, wenn alles, was eine Funktion/Methode benötigt, an einer Stelle ist. So findest du dich später besser zurrecht.
Ein anderer Underschied ist aber auch, dass im Beispiel deines Kollegen das Delegate handler nur dann Speicher belegt, wenn die Funktion gerade aufgerufen wird. Danach wird der Speicher wieder freigegeben. In deinem Beispiel liegt sie permanent im Speicher. Oder wenn du 5 Instanzen deiner Klasse hast, hast du somit 5 Delegates im Speicher. Das kann sich bei vielen Instanzen vllt. doch aufsummieren. Bei der Variante deines Kollegen sind es nur so viele, wie die Funktion gleichzeitig zu einem Zeitpunkt aufgerufen wird. Die Zahl kann damit auf 0 fallen. Das ist die andere Seite bei dem Thema.

Ich versteh allerdings nicht so ganz, warum überhaupt ein Delegate verwendet wird. Wenn ich, wie du sagst, eine Methode aus einer anderen Klasse aufrufen möchte, mach ich das auf direktem Wege:

C#:
class Foo
{
    void Bar()
    {
        Klasse.Irgendwas("Hallo");
    }
}
Dazu ist ein Delegate nicht notwendig.
 

Mr.Ed

Neues Mitglied
Vielen Dank für die Erklärung.

Dass ich die Funktion auch so aus eine anderen Klasse aufrufen kann ist mir klar. Ist ja auch viel einfacher als nen Delegaten dafür einzurichten :)

Aber ich wollte ja das Thema mit den Delegaten verstehen und sie nicht möglichst vermeiden.

Da käme ich dann aber auch zur nächsten Frage, wann ist denn der Einsatz von Delegaten absolut sinnvoll.
Beziehungsweise welchen Vorteil bieten Delegaten? Die Erklärung aus der MSDN ist da ja doch ein wenig unverständlich für mich. :unsure:
 

Mat

Mitglied
Kenne mich mit C# nicht so aus, aber ein bisschen mit Java. Und C# kann ja alles, was Java kann, und mehr. Deswegen frage ich mich, was dann der Unterschied zwischen Delegaten und Interfaces oder Vererbung ist?

Vielleicht hilft das dabei, den Nutzen von Delegaten zu ergründen und sinnvolle Anwendungsfälle zu finden.
 

dominik

Mitglied
Da käme ich dann aber auch zur nächsten Frage, wann ist denn der Einsatz von Delegaten absolut sinnvoll. Beziehungsweise welchen Vorteil bieten Delegaten?
Das ist eigentlich die richtige Fragestellung. Ob du Delegates "richtig" oder "falsch" verwendest, kann dir niemand sagen, weil es auf dein Programm und dessen Architektur ankommt. Nur weil dein Kollege sie üblicherweise anders verwendet, heißt das nicht, dass du sie falsch verwendest.

Delegates in C# sind nichts anderes als Function Pointer. Das ist ein uraltes Konzept, das von C über JS bis hin zu Go von etlichen Sprachen implementiert wurde. Vorteil ist beispielsweise, dass man nicht immer ganze Klassen oder Interfaces als Abhängigkeit definieren muss, sondern stattdessen auch Funktionen angeben kann. Du musst den Nutzen und die Mächtigkeit von Function Pointern und Closures verstehen - dann weißt du auch, wann Delegates für deinen Anwendungsfall sinnvoll sind. Ich persönlich habe recht lange dafür gebraucht ^^

Deswegen frage ich mich, was dann der Unterschied zwischen Delegaten und Interfaces oder Vererbung ist?
Delegates bilden eine Abhängigkeit auf eine Funktion ab, Interfaces bilden eine Abhängigkeit auf eine Klasse ab. Da es in Java keine Delegates gibt, wurden und werden Interfaces als Ersatz verwendet. Um eine typsichere Callback-Funktion zu implementieren, musste man ein Interface erstellen, das eine Funktion mit der gewünschten Signatur vorschreibt. Dieses Interface musste man dann mit einer anonymen Klasse implementieren, die man dann als Argument übergeben konnte.

Mittlerweile gibt es Functional Interfaces, die in Kombination mit Lambda-Expressions deutlich weniger Schreibarbeit machen und sich syntaktisch kaum von Delegates unterscheiden: https://www.baeldung.com/java-8-functional-interfaces
 
  • Like
Reaktionen: Mat

Rushh0ur

Neues Mitglied
Also ich sehe jetzt weder bei der einen noch bei der anderen Art und Weise der Verwendung ein Problem. In dem genannten Kontext ist es wie schon von anderen angemerkt relativ sinn frei.

Ich verwende Delegates gerne da, wo ich etwas an die übergeordnete Schicht signalisieren will, oder von dieser Laufzeitinformationen brauche, die sich ggf ändern können, und nicht etwaige Klassen schreiben möchte.

Beispiel (C# 7); hier verwende ich dann auch zu meist vordefinierte Action und Func Template Definitionen:
C#:
using System;
using System.Threading.Tasks;
                    
public class Program
{
    public static Task RunProcess(Action<int, int> ProgressUpdate = null)
    {
        return Task.Run( async () => {
            var max = 200;
            
            for (var current = 0; current < max; current += 20)
            {
                ProgressUpdate?.Invoke(current, max);
                await Task.Delay(50);
            }
            
            ProgressUpdate?.Invoke(max, max);
        });
    }
    
    public static void OnProgressUpdate(int current, int maximum)
    {
        Console.WriteLine("OnProgressUpdate {0} / {1}", current, maximum);
    }
    
    public static void Main()
    {
        Console.WriteLine("Function delegate demo.");
        
        Console.WriteLine("Run process task.");
        var task = RunProcess(OnProgressUpdate);
        Console.WriteLine("Process task running.");
        
        Console.WriteLine("Wait for completetion.");
        task.Wait();
        Console.WriteLine("Task completed. Exiting.");
    }
}
 

Mr.Ed

Neues Mitglied
Hey vielen Dank für die Tipps,

In dem genannten Kontext ist es wie schon von anderen angemerkt relativ sinn frei.
Der gewählte Kontext war ja nur ein Beispiel um den unterschied in der Verwendung zu zeigen, mehr nicht. Aber wenn weder das eine noch das andere verkehrt ist, beruhigt mich das schon ungemein. :)
 
Oben Unten