为什么在此示例中需要 "where T : class"?

Why is "where T : class" required in this example?

示例代码:

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。这段代码工作正常。

我的问题是,为什么方法需要 "where T : class" 约束?如果我删除它,我会得到编译时错误:

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

我会认为一切都是 "object",所以约束是不必要的?

需要约束,因为object只是一个引用类型;可以将值类型分配给 object 的原因是由于装箱(尽管从技术上讲,所有类型都继承自 System.Object)。

但是装箱与类型参数变化是不同的问题;具有无约束 T 的 IEnumerable<T> 无法转换为 IEnumerable<object>,因为值类型不支持方差。

顺便说一句,非泛型 FileHelperEngine 继承自(如 FileHelperEngine<object>)的 FileHelperEngine<T> 也有一个 T : class 约束。因此,由于仅支持引用类型,因此您不会因具有约束而丢失任何功能 - 理论上可以直接使用 FileHelperEngine<T> 而无需通过非泛型 class,因为中给出的方法示例已经是通用的:

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> 无效。 所以它只是防止类型不匹配。