5

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)
    {
        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) ...

  • 1
    See [Why does a Linq Cast operation fail when I have an implicit cast defined?](http://stackoverflow.com/questions/808725/why-does-a-linq-castt-operation-fail-when-i-have-an-implicit-cast-defined) and its linked threads. – Jeppe Stig Nielsen Jul 30 '14 at 06:44

1 Answers1

10

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();
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • :)) the ctor with int-param is private ... sorry mate ... no chance with that ... is there any other solution instead of the `.Select()`? –  Nov 03 '10 at 07:32
  • @Andreas, missed the private ctor. Select is your best bet here. It's really suited for this purpose as it represents a projection which is what needs to happen here – JaredPar Nov 03 '10 at 07:36