Я не могу понять, почему следующий код C # не компилируется.
Как видите, у меня есть статический универсальный метод Something с IEnumerable<T>
параметром (и T
он должен быть IA
интерфейсом), и этот параметр не может быть неявно преобразован в IEnumerable<IA>
.
Какое объяснение? (Я не ищу обходной путь, просто чтобы понять, почему это не работает).
public interface IA { }
public interface IB : IA { }
public class CIA : IA { }
public class CIAD : CIA { }
public class CIB : IB { }
public class CIBD : CIB { }
public static class Test
{
public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA
{
var bar = foo.ToList();
// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());
// This call is illegal
Something2(bar);
return bar;
}
private static void Something2(IEnumerable<IA> foo)
{
}
}
Ошибка, я попал в Something2(bar)
очередь:
Аргумент 1: невозможно преобразовать из System.Collections.Generic.List в System.Collections.Generic.IEnumerable.
c#
covariance
contravariance
BenLaz
источник
источник
T
ссылочными типами. Если вы используете это условие,where T: class, IA
оно должно работать. Связанный ответ содержит более подробную информацию.Something2(foo);
прямо. Чтобы понять это, не нужно идти вокруг,.ToList()
чтобы получитьList<T>
(T
это ваш параметр типа, объявленный универсальным методом) (aList<T>
- этоIEnumerable<T>
).Ответы:
Сообщение об ошибке недостаточно информативно, и это моя вина. Извини за это.
Проблема, с которой вы столкнулись, является следствием того факта, что ковариация работает только с ссылочными типами.
Вы, наверное, сейчас говорите «но
IA
это ссылочный тип». Да, это так. Но вы не сказали, чтоT
это равноIA
. Вы сказали, чтоT
это тип, который реализуетIA
, а тип значения может реализовывать интерфейс . Поэтому мы не знаем, сработает ли ковариация, и запрещаем ее.Если вы хотите, чтобы ковариация работала, вы должны сообщить компилятору, что параметр типа является ссылочным типом с
class
ограничением, а также сIA
ограничением интерфейса.В сообщении об ошибке действительно должно быть сказано, что преобразование невозможно, потому что ковариация требует гарантии ссылочного типа, поскольку это фундаментальная проблема.
источник
customers.Select(c=>c.FristName)
? В спецификации C # четко указано, что это ошибка разрешения перегрузки : набор применимых методов с именем Select, которые могут принимать эту лямбду, пуст. Но основная причина в том, чтоFirstName
это опечатка.Я просто хотел дополнить отличный инсайдерский ответ Эрика примером кода для тех, кто может быть не знаком с общими ограничениями.
Измените
Something
подпись следующим образом:class
ограничение должно быть первым .источник
primary_constraint ',' secondary_constraints ',' constructor_constraint
class
плохо, потому что означает «ссылочный тип», а не «класс». Я был бы более доволен чем-нибудь подробным, например,where T is not struct