Nie rozumiem tej sprawy:
public delegate int test(int i);
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
public test Fail()
{
Func<int, int> f = x => x;
return f; // <- code doesn't compile
}
Dlaczego kompilacja jest OK, gdy używam Invoke
metody, a nie OK, gdy wracam csharp Func<int,int>
bezpośrednio?
delegate void test1(int i);
idelegate void test2(int i);
Odpowiedzi:
Są dwie rzeczy, które musisz wiedzieć, aby zrozumieć to zachowanie.
System.Delegate
, ale różni delegaci mają różne typy i dlatego nie można ich przypisywać.Ponieważ różni delegaci mają różne typy, oznacza to, że nie można przypisać delegata jednego typu do drugiego.
Na przykład biorąc pod uwagę:
Następnie:
Pierwszy wiersz powyżej kompiluje OK, ponieważ używa specjalnej obsługi do przypisywania lambda lub metody do delegata.
W rzeczywistości kompilator skutecznie przepisał następującą linię:
Drugi wiersz powyżej nie kompiluje się, ponieważ próbuje przypisać wystąpienie jednego typu do innego niezgodnego typu.
Jeśli chodzi o typy, nie ma kompatybilnego przypisania pomiędzy
test1
itest2
ponieważ są to różne typy.Jeśli warto o tym pomyśleć, rozważ następującą hierarchię klas:
Poniższy kod nie będzie kompilować, choć
Test1
iTest2
wywodzą się z tej samej klasy bazowej:To wyjaśnia, dlaczego nie można przypisać jednego typu delegata do innego. To tylko normalny język C #.
Najważniejsze jest jednak zrozumienie, dlaczego możesz przypisać metodę lub lambda kompatybilnemu delegatowi. Jak wspomniano powyżej, jest to część obsługi języka C # dla delegatów.
Więc w końcu odpowiedz na twoje pytanie:
Gdy używasz
Invoke()
, przypisujesz wywołanie METHOD do delegata, korzystając ze specjalnej obsługi języka C # do przypisywania metod lub lambd do delegata zamiast próbować przypisać niezgodny typ - stąd kompilacja jest OK.Aby być całkowicie jasnym, kod, który kompiluje się w twoim OP:
Jest konwertowany koncepcyjnie na coś takiego:
Podczas gdy uszkodzony kod próbuje przypisać dwa niezgodne typy:
źródło
W drugim przypadku
f
jest typuFunc<int, int>
, ale mówi się, że metoda zwraca atest
. Są to typy niepowiązane (delegowane), które są wzajemnie niewymienne, więc występuje błąd kompilatora. Możesz przejść do tej sekcji specyfikacji języka i wyszukać „delegować”. Nie znajdziesz żadnej wzmianki o konwersjach między delegatami, którzy mają te same podpisy.W pierwszym przypadku
f.Invoke
jest to wyrażenie grupy metod , które w rzeczywistości nie ma typu. Kompilator C # konwertuje wyrażenia grupy metod na określone typy delegatów zgodnie z kontekstem, poprzez konwersję grupy metod .(Cytując tutaj piąty pocisk , podkreśl moje)
W takim przypadku jest konwertowany na
test
typ delegata.Innymi słowy,
return f
nie działa, ponieważf
ma już typ, alef.Invoke
nie ma jeszcze typu.źródło
Problem dotyczy zgodności typu:
Poniżej znajduje się definicja delegata Func z MSDN Sources:
public delegate TResult Func<in T, out TResult>(T arg);
Jeśli zauważysz, że nie ma bezpośredniego związku między Func wspomnianym powyżej a twoim zdefiniowanym Delegatem:
public delegate int test(int i);
Delegatów porównuje się za pomocą podpisu, który jest parametrami wejściowymi i wynikiem wyjściowym, ostatecznie Delegat jest wskaźnikiem funkcji, a dwie funkcje można porównać tylko poprzez podpis. W czasie wykonywania metoda wywoływana przez Func jest przypisywana
Test
delegatowi, ponieważ podpis jest taki sam i działa bezproblemowo. Jest to przypisanie wskaźnika funkcji, w którymTest
delegat będzie teraz wywoływał metodę wskazaną przez delegata FuncPomiędzy Func a testowanym delegatem nie ma zgodności typu / przypisania, Func nie może wypełnić w ramach reguł systemowych Type. Nawet jeśli jego wynik można przypisać i wypełnić
test delegate
tak, jak w pierwszym przypadku.źródło