Как уже упоминали другие, это очень зависит от драйвера. Похоже, нет способа проверить с помощью .Net API, существует ли порт, возвращенный GetPortNames (), на самом деле и действителен.
Что касается того, почему порты ведут себя так, я обнаружил, что некоторые драйверы USB-to-serial вызывают сбой приложения при внезапном отключении порта.
Другие драйверы, часто те, которые не аварийно завершают работу, будут сохранять порт в списке, пока ваше приложение не закроет его, а затем исчезнет. Попытка чтения или записи в устаревший порт (обычно) приведет к тайм-ауту или ошибкам. Предположительно, чтобы не вызывать сбой приложения, драйвер должен поддерживать устаревший порт, пока он еще открыт в приложении.
Если вы снова подключите порт, некоторые драйверы смогут даже повторно подключить его к вашему приложению, другие не будут распознавать порт, пока ваше приложение не закроет устаревший порт. Такое поведение при повторном подключении может быть несколько опасным, если порт исчез из-за перезагрузки устройства, потому что тогда он внезапно окажется в другом состоянии, чем ожидает ваше приложение, без явного указания на его сброс. По крайней мере, если вы получаете ошибки из порта, вы знаете, что что-то произошло.
Я также обнаружил, что если я забуду закрыть порт, он не исчезнет из списка до тех пор, пока сборщик мусора не сможет утилизировать объект SerialPort.