5

otrzymuje dwie implementacje metod porównania:Warunkowe operator i Porównanie Delegat

// compares by Key... 
private static int CompareByKey(KeyValuePair<int, string> x, KeyValuePair<int, string> y) 

{ 
    return x.Key.CompareTo(y.Key); 
} 

// compares by Value... 
private static int CompareByValue(KeyValuePair<int, string> x, KeyValuePair<int, string> y) 
{ 
    return x.Value.CompareTo(y.Value); 
} 

dlaczego nie następujące Operator warunkowy blok kodu kompilacji:

Comparison<KeyValuePair<int, string>> sortMethod; 
sortMethod = isSortByActualValue ? CompareByKey : CompareByValue; 

błąd kompilatora: „Typ wyrażenia warunkowego nie może być określone, ponieważ nie istnieje żadna niejawna konwersja między "grupą metod" a "grupą metod" "

Jednak równoważny blok kodu przy użyciu opcji if-else d OES nie ma żadnego problemu:

Comparison<KeyValuePair<int, string>> sortMethod; 
if (isSortByActualValue) 
    sortMethod = CompareByKey; 
else 
    sortMethod = CompareByValue; 

(dobre w obu zadaniach powyżej)

Tak samo operator warunkowy, jeśli rzucam delegata porównania:

Comparison<KeyValuePair<int, string>> sortMethod; 
sortMethod = isSortByActualValue ? (Comparison<KeyValuePair<int, string>>) CompareByKey : CompareByValue; 

(wszystko dobre w powyższe przypisanie, podczas rzucania, chociaż rzut był tylko na prawdziwej części)

+2

Jak są zdefiniowane kryteria CompareByAcutalValue i CompareByDisplayValue? Wyświetlasz tylko definicję CompareByKey i CompareByValue. –

+0

Fragment kodu w moim poście został zmodyfikowany dla zachowania przejrzystości. Nie zdawałem sobie sprawy, że zmieniłem nazwę (metody) tylko częściowo. Dzięki Eric, zaktualizowałem wszystkie odniesienia do CompareByActualValue do CompareByKey (i CompareByDisplayValue do CompareByValue). – Arun

Odpowiedz

7

Metoda błędu Th faktycznie mówi to wszystko, ale nie jest to całkiem intuicyjne. Jeśli używasz nazwy metody bez wywoływania tej metody, używasz grupy metod . "Grupa", ponieważ metoda może być przeciążona, a nazwa może wskazywać którąś z przeciążonych metod.

Teraz grupy metod są wymienialne niejawnie na delegata z pasującym podpisem, dlatego Twoje zadanie w if działa.

Jak dotąd, tak dobrze. Jednak operator warunkowy ?: musi wydedukować typ wspólny, do którego drugi i trzeci argument może zostać niejawnie przekonwertowany, i nie bierze pod uwagę wszystkich konwersji z tego powodu (miałoby to różne problemy). Po prostu sprawdza, czy oba argumenty mają ten sam typ, czy jedno z nich jest w domyśle wymienialne na drugie.

W tym przypadku tak nie jest: mimo że oba argumenty są grupami metod, to w rzeczywistości są to różne grupy metod z różnymi typami i nie można przekształcić jednej grupy metod w drugą. Mimo że oba można łatwo przekształcić w delegata, kompilator zabrania tego użycia.

Tak samo jest w przypadku innych typów, przy okazji:

object = someBool ? "" : New List<Integer>(); 

również nie skompilować, z tego samego powodu. I znowu, możemy zrobić to skompilować jawnie rzucając jeden z argumentów do wspólnego typu bazowego:

object = someBool ? (object) "" : New List<Integer>(); 
+1

+1, ale zmienilbym "potrzeby wyprowadzenia typu drugiego i trzeciego argumentu" to ", aby wydedukować typ wspólny, do którego drugi i trzeci argument może zostać niejawnie przekonwertowany" – phoog

+0

Dlaczego więc "nie jest" WartoścAlnaAktywna wartość ? CompareByKey: CompareByKey' compile? Czy to nie ta sama grupa metod? – svick

+0

@svick Nie istnieje konwersja z grupy metod do grupy metod, niezależnie od grupy metod. Powinienem był to wyjaśnić i jest to dość szczególny przypadek, ponieważ żadnemu typowi nie brakuje tego nawrócenia. Nie wiem, jak to jest dokładnie określone w specyfikacji C#. –

3

Jeśli masz wyrażenia jak twój CompareByKey, to nie ma żadnego konkretnego typu .NET, ale ma specjalny typ "grupa metod". To dlatego, że możesz mieć kilka metod o nazwie CompareByKey i nie jest jasne, który z nich chcesz (i działa dokładnie tak samo, nawet jeśli masz tylko jedną metodę). Nie jest też jasne, jakiego typu delegatów chcesz, np. Comparison<KeyValuePair<int, string>> lub Func<KeyValuePair<int, string>, int>.

Co można zrobić z grupami metod? Można ich użyć do jawnego utworzenia delegata (new Comparison<KeyValuePair<int, string>>(CompareByKey)) i są one również niejawnie wymienialne na delegatów. Właśnie dlatego działa Twoja wersja if.

Co to ma wspólnego z twoim problemem? Kiedy masz operator warunkowy, kompilator musi wykombinować typ całego wyrażenia i nie może użyć typu zmiennej, do której go przypiszesz (to nie działa inferencja typów w C#). A ponieważ oba wyrażenia są grupami metod, a grupy metod są traktowane jako różne typy bez żadnych niejawnych konwersji między sobą, nie można określić typu całego wyrażenia. Właśnie dlatego pojawia się błąd.

Znalazłeś poprawkę: nie używaj operatora warunkowego lub jawnie określ typ jednego z operandów za pomocą rzutowania (lub delegowanego konstruktora).