Czy możesz mi pomóc w zrozumieniu delegatów w języku C # i frameworku .NET? Próbowałem sprawdzić kod i stwierdziłem, że otrzymane wyniki były dla mnie nieoczekiwane. Oto ona:
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());
}
}
Odpowiedź brzmiała 0, ale nie 10. Dlaczego?
()
wywołałobyToString
.Func
s, było to zgadywanie :)static
metodę. Gdy reprezentuje metodę instancji, delegat przechowuje zarówno obiekt docelowy, na którym ma zostać wywołana metoda, jak i informacje o metodzie. Więc kiedy mówiszdel = I.ToString;
,del
będzie trzymał obiekt,I
który jest tutajInt32
(niezmienny typ wartości). Gdy używasz funkcji anonimowej,del = () => I.ToString();
kompilator tworzy metodę,static string xxx() { return I.ToString(); }
adel
obiekt przechowuje tę wygenerowaną metodę.Odpowiedzi:
Powód jest następujący:
Sposób deklarowania delegata wskazuje bezpośrednio na
ToString
metodę statycznej instancji int. Jest schwytany w czasie stworzenia.Jak Flindeberg wskazuje w komentarzach poniżej, każdy delegat ma cel i metodę, która ma zostać wykonana na miejscu docelowym.
W tym przypadku metodą do wykonania jest oczywiście
ToString
metoda. Interesującą częścią jest instancja, na której jest wykonywana metoda: jest to instancjaI
w momencie tworzenia, co oznacza, że delegat nie używaI
instancji do użycia, ale przechowuje odwołanie do samej instancji.Później zmieniasz
I
na inną wartość, po prostu przypisując jej nową instancję. Nie zmienia to w magiczny sposób instancji przechwyconej w Twoim delegacie, dlaczego miałoby to robić?Aby uzyskać oczekiwany wynik, musisz zmienić delegata na następujący:
static Func<string> del = new Func<string>(() => I.ToString());
W ten sposób delegat wskazuje na anonimową metodę, która jest wykonywana
ToString
na bieżącoI
w momencie wykonywania delegata.W tym przypadku metoda do wykonania jest metodą anonimową utworzoną w klasie, w której jest zadeklarowany delegat. Instancja ma wartość null, ponieważ jest metodą statyczną.
Przyjrzyj się kodowi, który kompilator generuje dla drugiej wersji delegata:
private static Func<string> del = new Func<string>(UserQuery.<.cctor>b__0); private static string cctor>b__0() { return UserQuery.I.ToString(); }
Jak widać, jest to normalna metoda, która coś robi . W naszym przypadku zwraca wynik wywołania
ToString
bieżącego wystąpieniaI
.źródło
Musisz przejść
I
do swojej funkcji, abyI.ToString()
mogła zostać wykonana w odpowiednim czasie (zamiast w momencie tworzenia funkcji).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)); } }
źródło
Oto, jak należy to zrobić:
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()); } } }
źródło
Delegat C # włącza hermetyzację obiektu i wystąpienia oraz metody. Deklaracja delegata definiuje klasę, która jest pochodną klasy System.Delegate. Wystąpienie delegata hermetyzuje listę wywołań, która jest listą co najmniej jednej metody, z których każda jest nazywana jednostką wywoływalną.
dowiedz się więcej formularz
http://asp-net-by-parijat.blogspot.in/2015/08/what-is-delegates-in-c-how-to-declare.html
źródło
Domyślam się, że int są przekazywane przez wartości, a nie odwołania, iz tego powodu podczas tworzenia delegata jest to delegat do metody ToString o bieżącej wartości „I” (0).
źródło
Foo
zamiastint
i zmienisz wierszI = 10
na to,I = new Foo(10)
uzyskasz dokładnie taki sam wynik, jak w przypadku bieżącego kodu.I.Value = 10
jest czymś zupełnie innym. Nie powoduje to przypisania nowej instancji doI
. Ale przypisanie nowej instancji doI
jest tutaj ważnym punktem.