Why does this cast-operation fail
i've got this struct
[Serializable]
public struct Foo : IConvertible, IXmlSerializable, IComparable, IComparable<Foo>
{
private readonly int _value;
private Foo(int id)
{
this._value = id;
}
private IConvertible ConvertibleValue
{
get
{
return this._value;
}
}
public int CompareTo(object obj)
{
if (obj is Foo)
{
var foo = (Foo) obj;
return this.CompareTo(foo);
}
return -1;
}
public int CompareTo(Foo other)
{
return this._value.CompareTo(other._value);
}
public TypeCode GetTypeCode()
{
return this._value.GetTypeCode();
}
bool IConvertible.ToBoolean(IFormatProvider provider)
{
return this.ConvertibleValue.ToBoolean(provider);
}
char IConvertible.ToChar(IFormatProvider provider)
{
return this.ConvertibleValue.ToChar(provider);
}
sbyte IConvertible.ToSByte(IFormatProvider provider)
{
开发者_Python百科 return this.ConvertibleValue.ToSByte(provider);
}
byte IConvertible.ToByte(IFormatProvider provider)
{
return this.ConvertibleValue.ToByte(provider);
}
short IConvertible.ToInt16(IFormatProvider provider)
{
return this.ConvertibleValue.ToInt16(provider);
}
ushort IConvertible.ToUInt16(IFormatProvider provider)
{
return this.ConvertibleValue.ToUInt16(provider);
}
int IConvertible.ToInt32(IFormatProvider provider)
{
return this.ConvertibleValue.ToInt32(provider);
}
uint IConvertible.ToUInt32(IFormatProvider provider)
{
return this.ConvertibleValue.ToUInt32(provider);
}
long IConvertible.ToInt64(IFormatProvider provider)
{
return this.ConvertibleValue.ToInt64(provider);
}
ulong IConvertible.ToUInt64(IFormatProvider provider)
{
return this.ConvertibleValue.ToUInt64(provider);
}
float IConvertible.ToSingle(IFormatProvider provider)
{
return this.ConvertibleValue.ToSingle(provider);
}
double IConvertible.ToDouble(IFormatProvider provider)
{
return this.ConvertibleValue.ToDouble(provider);
}
decimal IConvertible.ToDecimal(IFormatProvider provider)
{
return this.ConvertibleValue.ToDecimal(provider);
}
DateTime IConvertible.ToDateTime(IFormatProvider provider)
{
return this.ConvertibleValue.ToDateTime(provider);
}
string IConvertible.ToString(IFormatProvider provider)
{
return this.ConvertibleValue.ToString(provider);
}
object IConvertible.ToType(Type conversionType, IFormatProvider provider)
{
return this.ConvertibleValue.ToType(conversionType, provider);
}
XmlSchema IXmlSerializable.GetSchema()
{
return null;
}
void IXmlSerializable.ReadXml(XmlReader reader)
{
var stringId = reader.ReadElementContentAsString();
if (string.IsNullOrEmpty(stringId))
{
return;
}
this = int.Parse(stringId);
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
writer.WriteValue(this);
}
public static implicit operator int(Foo value)
{
return value._value;
}
public static implicit operator Foo(int value)
{
Foo foo;
if (value > 0)
{
foo = new Foo(value);
}
else
{
foo = new Foo();
}
return foo;
}
public override string ToString()
{
return this._value.ToString();
}
}
now i'm failing this:
var intList = new List<int>
{
1,
2,
3,
4
};
var fooList = intList.Cast<Foo>().ToList();
with
System.InvalidCastException: Specified cast is not valid. at System.Linq.Enumerable.d__aa`1.MoveNext() at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) ...
The reason why is that the Cast
function is written against generic types (i.e. not concrete types). It looks a bit like the following
public IEnumeralbe<T> Cast<T>(this IEnumerable source) {
foreach (object cur in source) {
yield return (T)cur;
}
}
The cast operation inside of Cast
can only be done on this generic information which does not include the specialzed cast operator on Foo
. Hence this code does not consider the implicit conversion here and instead essentially relies on CLR conversions only.
In order to get this working you need the cast to be done against the Foo
type directly. The best way to do this is with a select
var fooList = intList.Select(x => (Foo)x).ToList();
精彩评论