I have a generic class NamedValue<TValue>:
public class NamedValue<TValue>
{
public string Name { get; set; }
public TValue Value { get; set; }
}
I have a second generic class, NamedValueSource<TValue> that contains a List<NamedValue<TValue>>:
public class NamedValueSource<TValue>
{
public List<NamedValue<TValue>> NamedValues { get; set; }
public NamedValueSource()
{
NamedValues = GetNamedValues().Cast<NamedValue<TValue>>().ToList();
}
private IEnumerable<NamedValue<bool>> GetNamedValues()
{
var yesNamedValue = new NamedValue<bool> { Name = "Yes", Value = true };
var noNamedValue = new NamedValue<bool> { Name = "Yes", Value = false };
yield return yesNamedValue;
yield return noNamedValue;
}
}
The following test code works perfectly (the assertion passes):
public class Tester
{
public Tester()
{
var source = new NamedValueSource<bool>();
Debug.Assert(source.NamedValues[0].Name == "Yes");
}
}
Now, here’s the interesting part. If I attempt to perform the cast within GetNamedValues(), the code won’t compile:
public class NamedValueSourceFail<TValue>
{
public List<NamedValue<TValue>> NamedValues { get; set; }
public NamedValueSourceFail()
{
NamedValues = GetNamedValues().ToList();
}
private IEnumerable<NamedValue<TValue>> GetNamedValues()
{
var yesNamedValue = new NamedValue<bool> { Name = "Yes", Value = true };
var noNamedValue = new NamedValue<bool> { Name = "Yes", Value = false };
yield return (NamedValue<TValue>)yesNamedValue; // ERROR: cannot convert type
yield return (NamedValue<TValue>)noNamedValue; // ERROR: cannot convert type
}
}
Why does NamedValueSource<TValue> compile while NamedValueSourceFail<TValue> errors out? Specifically, why am I able to perform the cast using Linq but not with good ol’ parantheses?
Edit
In case it’s not entirely clear from the comment thread of the accepted answer, I simply needed to convert to object first, then I would be allowed to cast to NamedValue<TValue>. This is probably how the Linq Cast method works behind the scenes.
In your second example, you’re trying to convert
NamedValue<bool>toNamedValue<TValue>— this won’t work, because the conversion has to be valid for any type argument. You can’t convertNamedValue<bool>toNamedValue<int>orNamedValue<string>orNamedValue<AnythingElseOtherThanBool>.One solution is to make
NamedValueSource<TValue>abstract, as well as itsGetNamedValues()method, and then create a classBooleanNamedValueSource : NamedValueSource<bool>class to use in your test.In the linq case, the cast is not being done by the compiler; the cast occurs in a method that has already been compiled. All the compiler knows is that it is calling a method that takes
IEnumerable<bool>and returnsIEnumerable<TValue>. The specifics of that conversion are entirely invisible to the compiler.