Почему "где T: класс" требуется в этом примере?

Образец кода:

using System.Collections.Generic;
using FileHelpers;

....
private void Save<T>(string destFilename,  IEnumerable<T> data) where T : class    
{
    var engine = new FileHelperEngine((typeof(T)));


    engine.HeaderText = engine.GetFileHeader(); 
    engine.WriteFile(destFilename, data); // XX
}

В строке XX второй параметр для engine.WriteFile ожидает IEnumerable<объект>. Этот код работает нормально.

Мой вопрос: почему для метода требуется ограничение "где T: класс"? Если я удаляю его, я получаю ошибку времени компиляции:

Argument 2: cannot convert from
'System.Collections.Generic.IEnumerable<T>' to
'System.Collections.Generic.IEnumerable<object>'

Я бы подумал, что все было "объектом", и поэтому ограничение не было необходимости?

2 ответа

Решение

Ограничение необходимо, потому что object только ссылочный тип; типы значений причины могут быть назначены object из-за бокса (хотя технически все типы наследуются от System.Object).

Но бокс - это отдельная проблема от дисперсии параметров типа; IEnumerable<T> с неограниченным Т не может быть преобразован в IEnumerable<object> потому что дисперсия не поддерживается для типов значений.

Как в сторону, FileHelperEngine<T>, который не является родовым FileHelperEngine наследует от (как FileHelperEngine<object>), также имеет T : class ограничение. Таким образом, вы не пропускаете никакой функциональности, имея ограничение, так как в любом случае поддерживаются только ссылочные типы - теоретически можно просто использовать FileHelperEngine<T> непосредственно, не проходя через неуниверсальный класс, поскольку метод, приведенный в примере, уже является универсальным:

using System.Collections.Generic;
using FileHelpers;

....
private void Save<T>(string destFilename,  IEnumerable<T> data) where T : class    
{
    var engine = new FileHelperEngine<T>();


    engine.HeaderText = engine.GetFileHeader(); 
    engine.WriteFile(destFilename, data);
}

Вы собираетесь подать заявку T в FileHelperEngine<T> который уже имеет такое же ограничение, T : class, Компилятор может сказать, что если вы не наложите такое же ограничение на ваш метод, то T может быть недействительным для FileHelperEngine<T>, Так что это просто предотвращает несоответствия типов.

Другие вопросы по тегам