2010-06-02 10 views
10

Mam problem ze zrozumieniem tego, co jest przyczyną błędu kompilacji w poniższym kodzie:Dziwne zachowanie przełącznik w .NET 4

static class Program 
{ 
    static void Main() 
    { 
     dynamic x = ""; 
     var test = foo(x); 

     if (test == "test") 
     { 
      Console.WriteLine(test); 
     } 

     switch (test) 
     { 
      case "test": 
       Console.WriteLine(test); 
       break; 
     } 
    } 

    private static string foo(object item) 
    { 
     return "bar"; 
    } 
} 

Błąd pojawia jest w switch (test) line:

A switch expression or case label must be a bool, char, string, integral, 
enum, or corresponding nullable type. 

pokazy Intellisence mnie, że operacja foo zostanie rozwiązana w czasie wykonywania, co jest w porządku, ponieważ używam typu dynamicznego jako parametru. Jednak nie rozumiem, w jaki sposób warunek kompiluje się dobrze, gdy przełącznik nie.

Powyższy kod jest po prostu uproszczoną wersją tego, co mam w mojej aplikacji (VSTO), która pojawiła się po migracji aplikacji z VSTO3 do VSTO4, gdy jedna metoda w VSTO została zmieniona, aby zwracać wartości typu dynamic zamiast object.

Czy ktoś może mi wyjaśnić, na czym polega problem. Wiem, jak to rozwiązać, ale chciałbym zrozumieć, co się dzieje.

+0

Wygląda na to, że nie możesz ducktype przełącznika –

+0

Ponieważ 'switch' nie jest zdefiniowany dla każdego możliwego typu obiektu – thecoop

+0

Wszyscy wydają się odpowiadać tak, jakby pytanie brzmiało" Dlaczego nie mogę "przełączać' na 'dynamiczny '?" Myślę, że pytanie powinno brzmieć "Dlaczego" test "jest na początku" dynamiczny "? Rozumiem, że * jeśli * 'foo' ma przeciążenia, które zwróciły różne typy,' test' musiałby być "dynamiczny"; ale ponieważ to * nie *, nadal mam problem z ustaleniem odpowiedzi na "prawdziwe" pytanie tutaj. –

Odpowiedz

10

Ponieważ wywołujesz metodę dynamicznie, wynikiem jest także dynamic (jako że wartość zwracana może być dowolna z wartości - nie wiadomo do czasu wykonania). I nie można switch na typ zmiennej dynamic.

+0

I jest w porządku na 'if' na' dynamic'? – RaYell

+0

@RaYell: Nie "' if "na' dynamic' "- porównujesz dla równości' == 'na' dynamic'. To jest dobrze zdefiniowane. – Niki

+0

OK, to ma sens. – RaYell

0

To jest pewne nieoczekiwane zachowanie - oczekiwałbym, że var zostanie ustawione na metodę, która jawnie zwraca ciąg, aby poprawnie wywnioskować typ łańcucha. No cóż .....

Jeśli wymienić:

var test = foo (x);

z:

test łańcuchowy = foo (x);

wszystkie kompilacje, jak wiesz.

Jest to bezpieczne, ponieważ zadeklarowałeś foo() jako zwracanie ciągu znaków, i być może trochę bardziej intuicyjnie czytasz na dłuższą metę.

+0

"var" nie może zostać rozwiązany w czasie wykonywania, ponieważ x jest dynamiczny. Mogą występować liczne przeciążenia "foo", które mają różne parametry i typy zwracane.Dokładnie to, co się dzieje, nie może zostać rozwiązane, dopóki nie zostanie znany typ x, który nie nastąpi, dopóki nie zostanie uruchomiony. co tak naprawdę się dzieje, to, że var zostaje rozwiązany na "dynamiczny", dlatego nie można go użyć w przełączniku. Jeśli najedziesz wskaźnikiem myszy na "var", zobaczysz, że studio graficzne rozstrzyga "dynamiczne". –

+0

Tak - widzę to. Sądzę, że właśnie założyłem, że wnioskowanie var było mądrzejsze w obliczu obecności pojedynczej metody w zakresie, w którym wywołano wywołanie metody. Ale wiesz, co mówią o założeniach .... =) –

3

Typ wyrażenia przełącznika jest oceniany przez kompilator podczas kompilacji. Typ dynamic jest oceniany w środowisku wykonawczym, więc kompilator nie może zweryfikować, czy jest (lub jest do zmieniania) jednym z dozwolonych typów (który, zgodnie z C# 4 Language Specification jest sbajtowy, bajtowy, krótki, ushortowy, int, uint, długi, ulong, bool, char, string lub wyliczenie typu).

2

Jak mówi Matt Ellen, ale z nieco większym tłem.

Na rachunku switch: od C# Language Specification v4.0:

typ Prezesów z switch oświadczenie jest ustanowiony przez wyrażenie switch.

  • Jeżeli typ ekspresji przełącznika jest sbyte, byte, short, ushort, int, uint, long, ulong, bool, char, string, albo wyliczenia typu, czy to pustych typ odpowiadający jednemu z tych typów, to jest typ rządzący instrukcją switch.
  • W przeciwnym razie dokładnie jedna niejawna konwersja zdefiniowane przez użytkownika (§6.4) musi istnieć od rodzaju ekspresji przełączyć się na jeden z następujących możliwych typów regulujących: sbyte, byte, short, ushort, int, uint, long, ulong, char, string lub typu zerowalnego odpowiadającego jednemu z tych typów.
  • W przeciwnym razie, jeśli nie istnieje taka niejawna konwersja lub istnieje więcej niż jedna taka niejawna konwersja, pojawia się błąd podczas kompilacji.

Na rachunku if wyrażenie jest oceniane jako logicznej operacji. Ewaluacja wyrażenia jest odroczona do czasu wykonywania ze względu na użycie dynamic w wywołaniu metody w przypisaniu zmiennych. Z powyższej specyfikacji wygląda na to, że switch wymaga oceny typów przełączników podczas kompilacji.

0

Przełączniki obsługują wyłącznie numery, znaki, nazwy i ciągi znaków. dynamic to żadna z tych rzeczy. Jeśli założymy, że x jest ciągiem znaków, można po prostu rzucić go:

dynamic x = ""; 
string test = (string)foo(x); 

Będziesz po prostu błąd wykonania, jeśli tak nie jest.