2012-07-03 11 views
18

Próbuję użyć operatora warunkowego (trójkowego) do przypisania odpowiedniego wyrażenia lambda do zmiennej, w zależności od warunku, ale pojawia się błąd kompilatora: Typ Wyrażenia warunkowego nie można określić, ponieważ nie istnieje żadna niejawna konwersja między wyrażeniem lambda i wyrażeniem lambda. Mogę użyć zwykłego if-else, aby rozwiązać ten problem, ale operator warunkowy ma dla mnie więcej sensu (w tym kontekście), sprawiłby, że kod byłby bardziej zwięzły, przynajmniej chciałbym poznać powody, dla których nie działa ". t działa.Przypisywanie wyrażenia lambda za pomocą operatora warunkowego (trójkowego)

// this code compiles, but is ugly! :) 
Action<int> hh; 
if (1 == 2) hh = (int n) => Console.WriteLine("nope {0}", n); 
else hh = (int n) => Console.WriteLine("nun {0}", n); 

// this does not compile 
Action<int> ff = (1 == 2) 
    ? (int n) => Console.WriteLine("nope {0}", n) 
    : (int n) => Console.WriteLine("nun {0}", n); 
+0

Dziękuję za Twoją terminowość rich.okelly, Nikhil Agrawal, Romain Verdier i Alex! Wszystkie twoje odpowiedzi były poprawne (skompiluj i podaj poprawny wynik), ale mój wybór trafia do bogatych.zwykle z powodu jego wyjaśnienia. –

Odpowiedz

18

C# kompilator próbuje stworzyć lambdy niezależnie i nie można jednoznacznie określić typ.Casting może poinformować kompilator, który typ do używania:

Action<int> ff = (1 == 2) 
    ? (Action<int>)((int n) => Console.WriteLine("nope {0}", n)) 
    : (Action<int>)((int n) => Console.WriteLine("nun {0}", n)); 
15

To zadziała.

Action<int> ff = (1 == 2) 
? (Action<int>)((int n) => Console.WriteLine("nope {0}", n)) 
: (Action<int>)((int n) => Console.WriteLine("nun {0}", n)); 

Istnieją dwa problemy tutaj

  1. Expression
  2. Ternary Operator

1. Problem z ekspresją

Kompilator mówiąc dokładnie, co jest nie tak - 'Type of conditional expression cannot be determined because there is no implicit conversion between 'lambda expression' and 'lambda expression'.

Oznacza to, że napisałeś wyrażenie lambda, a wynikowa zmienna to także wyrażenie lambda.

Wyrażenie lambda nie ma określonego typu - po prostu można go przekształcić w drzewo wyrażeń.

Wyrażenie członkiem-access (czyli to, co starasz się zrobić) jest dostępna tylko w formach

primary-expression . identifier type-argument-list(opt) 
predefined-type . identifier type-argument-list(opt) 
qualified-alias-member . identifier type-argument-list(opt) 

... i wyrażenie lambda nie jest podstawowym wyrazem.

2. Problem z Ternary Operator

Jeśli robimy

bool? br = (1 == 2) ? true: null; 

Powoduje błędu mówiąc dokładnie jak twoje. 'Type of conditional expression cannot be determined because there is no implicit conversion between 'bool' and '<null>'

Ale błąd zniknie, jeśli robimy to

bool? br = (1 == 2) ? (bool?)true: (bool?)null; 

Casting z jednej strony będą również pracować

bool? br = (1 == 2) ? (bool?)true: null; 

LUB

bool? br = (1 == 2) ? true: (bool?)null; 

Twoim przypadku

Action<int> ff = (1 == 2) 
? (Action<int>)((int n) => Console.WriteLine("nope {0}", n)) 
: ((int n) => Console.WriteLine("nun {0}", n)); 

LUB

Action<int> ff = (1 == 2) 
? ((int n) => Console.WriteLine("nope {0}", n)) 
: (Action<int>)((int n) => Console.WriteLine("nun {0}", n)); 
+0

+1 szybka i doskonała – Habib

+0

świetna odpowiedź, prosto do rzeczy z czystymi przykładami ... dziękuję – Dal

+0

@Dal: Dzięki. :) –

3

zasadzie taką samą odpowiedź jak inni, w innej formie

Action<int> ff = (1 == 2) 
? new Action<int>(n => Console.WriteLine("nope {0}", n)) 
: new Action<int>(n => Console.WriteLine("nun {0}", n)); 
4

W rzeczywistości, z typu wnioskowania można:

  • Użyj zmiennej zmiennej lokalnej
  • odrzuć tylko pierwsze wyrażenie operatora trójskładnikowego
  • Pomiń typ parametru lambda, ponieważ można go wywnioskować:

Wynik jest znacznie bardziej zwięzły. (Pozwalam ci zdecydować, czy jest to bardziej czytelne.)

var ff = condition 
      ? (Action<int>)(n => Console.WriteLine("nope {0}", n)) 
      : n => Console.WriteLine("nun {0}", n);