Sample code :
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
}
At line XX, the 2nd parameter to engine.WriteFile is expecting an IEnumerable<object>. This code works ok.
My question is, why is the "where T : class" constraint required on the method ? If I remove it, I get the compile time error :
Argument 2: cannot convert from
'System.Collections.Generic.IEnumerable<T>' to
'System.Collections.Generic.IEnumerable<object>'
I would have thought that everything was an "object", and so that the constraint was not necessary ?
The constraint is needed because object
is a reference type only; the reason value types can be assigned to object
is due to boxing (even though, technically, all types inherit from System.Object
).
But boxing is a separate issue from type parameter variance; an IEnumerable<T>
with an unconstrained T cannot be converted to an IEnumerable<object>
because variance is not supported for value types.
As an aside, FileHelperEngine<T>
, which the non-generic FileHelperEngine
inherits from (as FileHelperEngine<object>
), also has a T : class
constraint. So you're not missing any functionality by having the constraint since only reference types are supported anyway — one could theoretically just use FileHelperEngine<T>
directly without going through the non-generic class, since the method given in the sample is already generic:
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);
}