Выражение типа T не может обрабатываться шаблоном типа X
Я обновил свой проект до целевого С# 7 и использовал Visual Studio 2017 RC для реализации соответствия шаблонов в моем решении. После этого были введены некоторые ошибки, связанные с сопоставлением шаблонов с общими параметрами.
Рассмотрим следующий код:
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;
}
}
Оба оператора if
и оператор case
создают ошибку компиляции.
Выражение типа T не может обрабатываться шаблоном типа KeepalivePacket
Если я впервые применил параметр для ввода object
, то сопоставление шаблонов будет работать так, как ожидалось. Затем Roslyn отмечает, что литье object
является избыточным.
if ((object)packet is KeepalivePacket keepalive)
{
// This works
}
Эта ошибка применяется только к общим параметрам и переменным. Roslyn, похоже, не знает об этой проблеме, так как рекомендует менять код для использования сопоставления шаблонов с помощью анализатора и позволяет мне применять "исправление кода", приводящее к повреждению кода.
Ответы
Ответ 1
Как объясняется Нилом Гафтером от Microsoft:
Причина, по которой он не работает, заключается в отсутствии преобразования (явного или неявного), определенного из T в KeepalivePacket. Соответствие шаблону требует, чтобы такое преобразование существовало, поскольку оно определено в терминах оператора трансляции, для которого требуется преобразование. Спецификация языка и компилятор согласны с тем, что никакого преобразования не существует. Мне кажется странным, что спецификация языка определена так, что здесь нет (явного) преобразования. Мы посмотрим, что мы можем с этим поделать.
Мы не собираемся ничего с этим делать на С# 7. Вам нужно будет добавить бросок к вашему коду, чтобы обойти его. Как только у нас будут рекурсивные шаблоны, это может быть труднее обойти. Более того, неудобное языковое правило, лежащее в основе этой проблемы (т.е. Отсутствие преобразования из T в KeepalivePacket), не имеет большого смысла.