Mam następujący kod:
Func<string, bool> comparer = delegate(string value) {
return value != "0";
};
Jednak następujące elementy nie są kompilowane:
var comparer = delegate(string value) {
return value != "0";
};
Dlaczego kompilator nie może dowiedzieć się, że jest to plik Func<string, bool>
? Pobiera jeden parametr łańcuchowy i zwraca wartość logiczną. Zamiast tego daje mi błąd:
Nie można przypisać metody anonimowej do zmiennej lokalnej o niejawnym typie.
Zgaduję, że jeśli skompilowano wersję var , brakowałoby spójności, gdybym miał:
var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
return false;
};
Powyższe nie miałoby sensu, ponieważ Func <> pozwala tylko na 4 argumenty (w .NET 3.5, którego używam). Być może ktoś mógłby wyjaśnić problem. Dzięki.
Func<>
akceptuje do 16 argumentów.Func<string, bool>
?Converter<string, bool>
Dla mnie wygląda na to!Dim comparer = Function(value$) value <> "0"
Odpowiedzi:
Inni już zauważyli, że istnieje nieskończenie wiele możliwych typów delegatów, o których mogliście mieć na myśli; co jest takiego specjalnego
Func
, że zasługuje na domyślny zamiastPredicate
lubAction
czy jakakolwiek inna możliwość? A w przypadku lambd, dlaczego jest oczywiste, że intencją jest wybór formy delegata, a nie formy drzewa wyrażeń?Ale możemy powiedzieć, że
Func
jest to coś specjalnego i że wywnioskowanym typem lambda lub metody anonimowej jest Func czegoś. Nadal mielibyśmy różnego rodzaju problemy. Jakie typy chciałbyś wywnioskować w następujących przypadkach?Nie ma
Func<T>
typu, który cokolwiek przyjmowałby ref.Nie znamy typu parametru formalnego, chociaż znamy zwrot. (A może my? Czy zwrot jest int? Long? Short? Byte?)
Nie znamy typu zwrotu, ale nie może to być nieważne. Typ zwracany może być dowolnym typem referencyjnym lub dowolnym typem wartości dopuszczającej wartość null.
Ponownie nie znamy typu zwracanego, a tym razem może być on nieważny.
Czy ma to być wyrażenie lambda zwracające void, czy coś, co zwraca wartość, która została przypisana do q? Obie są legalne; który powinniśmy wybrać?
Teraz możesz powiedzieć, cóż, po prostu nie obsługuj żadnej z tych funkcji. Po prostu obsługuj „normalne” przypadki, w których typy można opracować. To nie pomaga. Jak to ułatwia mi życie? Jeśli ta funkcja czasami działa, a czasami zawodzi, nadal muszę napisać kod, aby wykryć wszystkie te sytuacje awaryjne i podać znaczący komunikat o błędzie dla każdego. Nadal musimy określić całe to zachowanie, udokumentować je, napisać testy i tak dalej. Jest to bardzo kosztowna funkcja, która oszczędza użytkownikowi może pół tuzina naciśnięć klawiszy. Mamy lepsze sposoby na dodanie wartości do języka niż spędzanie dużo czasu na pisaniu przypadków testowych dla funkcji, która nie działa przez połowę czasu i nie zapewnia prawie żadnych korzyści w przypadkach, gdy działa.
Sytuacja, w której jest to rzeczywiście przydatne, to:
ponieważ nie ma „wypowiadalnego” typu dla tej rzeczy. Ale cały czas mamy ten problem i po prostu używamy wnioskowania o typie metody, aby wydedukować typ:
a teraz wnioskowanie o typie metody sprawdza, czym jest typ func.
źródło
Tylko Eric Lippert wie na pewno, ale myślę, że to dlatego, że podpis typu delegata nie określa jednoznacznie typu.
Rozważ swój przykład:
Oto dwa możliwe wnioski dotyczące tego, co
var
powinno być:Który z nich powinien wywnioskować kompilator? Nie ma dobrego powodu, aby wybrać jedną lub drugą. I chociaż a
Predicate<T>
jest funkcjonalnym odpowiednikiem aFunc<T, bool>
, to wciąż są różnymi typami na poziomie systemu typów .NET. W związku z tym kompilator nie może jednoznacznie rozstrzygnąć typu delegata i musi zakończyć się niepowodzeniem wnioskowania o typie.źródło
Eric Lippert ma na ten temat stary post , w którym mówi
źródło
Różni delegaci są uważani za różne typy. np.
Action
jest inny niżMethodInvoker
, a wystąpieniaAction
nie można przypisać do zmiennej typuMethodInvoker
.Tak więc, biorąc pod uwagę anonimowego delegata (lub lambda)
() => {}
, czy jest to anAction
czy aMethodInvoker
? Kompilator nie może powiedzieć.Podobnie, jeśli zadeklaruję typ delegata pobierającego
string
argument i zwracającego abool
, skąd kompilator będzie wiedział, że naprawdę chcesz miećFunc<string, bool>
typ delegata zamiast mojego typu delegata? Nie może wywnioskować typu delegata.źródło
Poniższe punkty pochodzą z MSDN w odniesieniu do zmiennych lokalnych wpisanych niejawnie:
Dokumentacja MSDN: zmienne lokalne wpisane niejawnie
Biorąc pod uwagę następujące kwestie dotyczące metod anonimowych:
Dokumentacja MSDN: metody anonimowe
Podejrzewałbym, że skoro metoda anonimowa może w rzeczywistości mieć różne sygnatury metody, kompilator nie jest w stanie poprawnie wywnioskować, jaki byłby najbardziej odpowiedni typ do przypisania.
źródło
Mój post nie odpowiada na rzeczywiste pytanie, ale odpowiada na podstawowe pytanie:
„Jak uniknąć konieczności wpisywania jakiegoś niezręcznego typu
Func<string, string, int, CustomInputType, bool, ReturnType>
?” [1]Będąc leniwym / hackim programistą, eksperymentowałem z użyciem
Func<dynamic, object>
- który przyjmuje pojedynczy parametr wejściowy i zwraca obiekt.W przypadku wielu argumentów możesz użyć tego w następujący sposób:
Wskazówka: możesz użyć,
Action<dynamic>
jeśli nie musisz zwracać obiektu.Tak, wiem, że prawdopodobnie jest to sprzeczne z zasadami programowania, ale ma to sens dla mnie i prawdopodobnie dla niektórych programistów Pythona.
Jestem całkiem nowicjuszem w delegatach ... po prostu chciałem podzielić się tym, czego się nauczyłem.
[1] Zakłada się, że nie wywołujesz metody, która wymaga predefiniowanego
Func
parametru, w takim przypadku będziesz musiał wpisać ten fugly string: /źródło
A co z tym?
źródło