Können Sie mir in C # -Sprache und .NET Framework helfen, Delegaten zu verstehen? Ich habe versucht, einen Code zu überprüfen, und festgestellt, dass die Ergebnisse, die ich erhalten habe, für mich unerwartet waren. Hier ist es:
class Program
{
public static int I = 0;
static Func<string> del = new Func<string>(I.ToString);
static void Main(string[] args)
{
I = 10;
Console.WriteLine("{0}", del());
}
}
Die Antwort war 0, aber nicht 10. Warum?
()
würde aufrufenToString
.Func
s benutzt, war eine Vermutung :)static
Methode verweisen . Wenn es sich um eine Instanzmethode handelt, enthält der Delegat sowohl das "Ziel" -Objekt, für das die Methode aufgerufen werden soll, als auch die Methodeninformationen. Wenn Sie also sagendel = I.ToString;
, enthält derdel
das Objekt,I
das hier einInt32
(unveränderlicher Werttyp) ist. Wenn Sie eine anonyme Funktion verwenden, erstelltdel = () => I.ToString();
der Compiler eine Methodestatic string xxx() { return I.ToString(); }
und dasdel
Objekt enthält diese generierte Methode.Antworten:
Der Grund ist folgender:
Die Art und Weise, wie Sie den Delegaten deklarieren, verweist direkt auf die
ToString
Methode der statischen int-Instanz. Es wird zum Zeitpunkt der Erstellung erfasst.Wie flindeberg in den Kommentaren unten ausführt, hat jeder Delegierte ein Ziel und eine Methode, die auf dem Ziel ausgeführt werden soll.
In diesem Fall ist die auszuführende
ToString
Methode offensichtlich die Methode. Der interessante Teil ist die Instanz, auf der die Methode ausgeführt wird: Es ist die InstanzI
zum Zeitpunkt der Erstellung, was bedeutet, dass der DelegatI
die Instanz nicht verwendet , um sie zu verwenden, sondern den Verweis auf die Instanz selbst speichert.Später wechseln Sie
I
zu einem anderen Wert und weisen ihm im Grunde eine neue Instanz zu. Dies ändert die in Ihrem Delegaten erfasste Instanz nicht auf magische Weise. Warum sollte dies der Fall sein?Um das erwartete Ergebnis zu erzielen, müssen Sie den Delegaten folgendermaßen ändern:
static Func<string> del = new Func<string>(() => I.ToString());
Auf diese Weise verweist der Delegat auf eine anonyme Methode, die zum Zeitpunkt der Ausführung des Delegaten
ToString
auf dem aktuellen Stand ausgeführt wirdI
.In diesem Fall ist die auszuführende Methode eine anonyme Methode, die in der Klasse erstellt wurde, in der der Delegat deklariert ist. Die Instanz ist null, da es sich um eine statische Methode handelt.
Sehen Sie sich den Code an, den der Compiler für die zweite Version des Delegaten generiert:
private static Func<string> del = new Func<string>(UserQuery.<.cctor>b__0); private static string cctor>b__0() { return UserQuery.I.ToString(); }
Wie Sie sehen können, ist es eine normale Methode, die etwas tut . In unserem Fall wird das Ergebnis des Aufrufs
ToString
der aktuellen Instanz von zurückgegebenI
.quelle
Sie müssen an
I
Ihre Funktion übergeben, damit dieseI.ToString()
zum richtigen Zeitpunkt ausgeführt werden kann (anstatt zum Zeitpunkt der Erstellung der Funktion).class Program { public static int I = 0; static Func<int, string> del = num => num.ToString(); static void Main(string[] args) { I = 10; Console.WriteLine("{0}", del(I)); } }
quelle
So sollte das gemacht werden:
using System; namespace ConsoleApplication1 { class Program { public static int I = 0; static Func<string> del = new Func<string>(() => { return I.ToString(); }); static void Main(string[] args) { I = 10; Console.WriteLine("{0}", del()); } } }
quelle
C # -Delegate aktivieren kapselt sowohl ein Objekt als auch eine Instanz und eine Methode. Eine Delegate-Deklaration definiert eine Klasse, die von der Klasse System.Delegate abgeleitet ist. Eine Delegateninstanz kapselt eine Aufrufliste, bei der es sich um eine oder mehrere Listenmethoden handelt, von denen jede als aufrufbare Entität bezeichnet wird.
Erfahren Sie mehr Form
http://asp-net-by-parijat.blogspot.in/2015/08/what-is-delegates-in-c-how-to-declare.html
quelle
Ich vermute, dass int von Werten übergeben wird, die keine Referenzen sind. Aus diesem Grund ist es beim Erstellen des Delegaten ein Delegat für die Methode ToString des aktuellen Werts von "I" (0).
quelle
Foo
anstelle von verwendenint
und die ZeileI = 10
in ändernI = new Foo(10)
würden, hätten Sie genau das gleiche Ergebnis wie mit dem aktuellen Code.I.Value = 10
ist etwas ganz anderes. Dies weist keine neue Instanz zuI
. Das Zuweisen einer neuen InstanzI
ist hier jedoch der wichtige Punkt.