Вчера исправлял баг, проявил он себя весьма интересно. Но продемонстрировать его можно на достаточно простом примере:
Т.к. мы не задали ограничений на T, то и IEnumerable тоже приводится к T объявленному в первом методе. Накладывание ограничений на T позволило бы узнать о этой проблеме на этапе компиляции. Изменим код:
Error CS0311 The type 'ConsoleApp1.Program.Demo[]' cannot be used as type parameter 'T' in the generic type or method 'Program.Print(T)'. There is no implicit reference conversion from 'ConsoleApp1.Program.Demo[]' to 'ConsoleApp1.Program.Demo'.
Как написано в заголовке, надо быть аккуратнее с Generic, максимально накладывать на них ограничения и не использовать в перегруженных методах, особенно в таком виде. А то вместо строгой типизации получим не строгую.
static void Main(string[] args)
{
Print(new[] { 1, 2, 3 });
Console.ReadKey();
}
static void
Print<T>(T t)
{
Console.WriteLine(t);
}
static void
Print<T>(IEnumerable<T> t)
{
foreach (var item in t)
{
Console.WriteLine(item);
}
}
При запуске вместо ожидаемых 1, 2, 3 мы увидим:Т.к. мы не задали ограничений на T, то и IEnumerable
class Demo
{
public int X { get; set; }
}
static void Main(string[] args)
{
Print(new[] { new Demo { X = 1 }, new Demo { X = 2 }, new Demo { X = 3 } });
Console.ReadKey();
}
static void
Print<T>(T t) where T : Demo
{
Console.WriteLine(t);
}
static void
Print<T>(IEnumerable<T> t) where T : Demo
{
foreach (var item in t)
{
Console.WriteLine(item);
}
}
В данном примере я явно указал к чему должен приводиться T (к Demo или его потомкам). И вот вместо ошибки времени выполнения, мы получаем ошибку компиляции:Error CS0311 The type 'ConsoleApp1.Program.Demo[]' cannot be used as type parameter 'T' in the generic type or method 'Program.Print
Как написано в заголовке, надо быть аккуратнее с Generic, максимально накладывать на них ограничения и не использовать в перегруженных методах, особенно в таком виде. А то вместо строгой типизации получим не строгую.
А смысл от параметра в методе, не использующем этот параметр? Если уберем его, полагаю, все прекрасно скомпилируется и будет работать как ожидается.
ОтветитьУдалитьВ смысле не использующемся? t маленькое используется для вывода значений в консоль. То что особенности T большого не используются, ну так это демо пример, важно проблему показать. А так можно внутри написать не просто вывод, а для последнего фрагмента кода, например так: Console.WriteLine(item.X);
Удалитьдумаю вопрос бы к тому, что в типе аргумента метода Print IEnumerable использует не Generic тип, по этому во 2 методе T не имеет смысла.
УдалитьБлин, блогер проглатил скобки, сейчас попробую поправить.
УдалитьПоправил
Удалить