2017-01-03 19 views
17

Zaktualizowałem swój projekt do C# 7 i użyłem Visual Studio 2017 RC do implementacji dopasowywania wzorców w moim rozwiązaniu. Po wykonaniu tej czynności wprowadzono błędy dotyczące dopasowywania wzorców z parametrami ogólnymi.Wyrażenie typu T nie może być obsługiwane przez wzorzec typu X

Rozważmy następujący kod:

public class Packet 
{ 
} 

public class KeepalivePacket : Packet 
{ 
} 

public void Send<T>(T packet) 
    where T : Packet 
{ 
    if (packet is KeepalivePacket keepalive) 
    { 
     // Do stuff with keepalive 
    } 

    switch (packet) 
    { 
     case KeepalivePacket keepalivePacket: 
      // Do stuff with keepalivePacket 
      break; 
    } 
} 

Zarówno oświadczenie if oraz oświadczenie case produkować błąd kompilacji.

Wyrazem typu T nie mogą być obsługiwane przez wzorzec typu KeepalivePacket

Gdybym pierwszy rzuci parametru do wpisywania object wzorca dopasowania działa zgodnie z oczekiwaniami. Roslyn następnie zaznacza obsadę jako object jako zbędną.

if ((object)packet is KeepalivePacket keepalive) 
{ 
    // This works 
} 

Ten błąd ma zastosowanie tylko do ogólnych parametrów i zmiennych. Wydaje się, że Roslyn nie zdaje sobie sprawy z tego problemu, ponieważ zaleca zmianę kodu w celu użycia dopasowywania wzorców za pomocą analizatora i pozwala mi zastosować "poprawkę kodu", co skutkuje zepsutym kodem.

+0

Wygląda na * zły projekt *, jeśli musisz włączyć typ obiektu. W rzeczywistości operator 'is' jest przez niektórych już uważany za * nieprzyjemny zapach * ... –

+3

@WillemVanOnsem musi być wystarczająco dużo przypadków użycia do dopasowania wzorca dla zespołu C#, aby dodać go do specyfikacji, nie? –

+0

, po prostu dlatego, że w większości zastosowań przemysłowych nie można najpierw zaprojektować całej rzeczy: jest zbyt skomplikowana. Ale właściwie każdy operator "jest" itp. Jest lepiej zastąpiony dynamicznymi powiązaniami, ponieważ są one bardziej bezpieczne dla typów. –

Odpowiedz

12

Jak explained by Neal Gafter firmy Microsoft:

Powodem nie działa jest to, że nie ma konwersji (explicite lub implicite) określona z T na KeepalivePacket. Dopasowywanie wzorców wymaga takiej konwersji, która jest zdefiniowana w kategoriach operatora rzutowania, który wymaga konwersji. Specyfikacja języka i kompilator zgadzają się, że nie istnieje żadna konwersja. Wydaje mi się dziwne, że specyfikacja języka jest zdefiniowana w taki sposób, że nie istnieje tu żadna (jawna) konwersja. Przyjrzymy się, co możemy z tym zrobić.

Nic nie zrobimy w tej sprawie w C# 7. Będziesz musiał dodać rzut do kodu, aby obejść go. Gdy mamy rekursywne wzorce, może to być trudniejsze do obejścia. Co więcej, niezręczna reguła językowa, która leży u podstaw tego problemu (tj. Że nie ma konwersji z T na KeepalivePacket) nie ma większego sensu.

Powiązane problemy