c# - 为什么这个转换操作失败

标签 c# linq casting 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();
    }
}

现在我失败了:

var intList = new List<int>
{
    1,
    2,
    3,
    4
};
var fooList = intList.Cast<Foo>().ToList();

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

最佳答案

原因是 Cast 函数是针对泛型类型(即非具体类型)编写的。看起来有点像下面

public IEnumeralbe<T> Cast<T>(this IEnumerable source) { 
  foreach (object cur in source) {
    yield return (T)cur;
  }
}

Cast 中的强制转换操作只能在这个通用信息上完成,不包括 Foo 上的特殊强制转换运算符。因此,此代码不考虑此处的隐式转换,而是本质上仅依赖 CLR 转换。

为了实现此功能,您需要直接针对 Foo 类型进行强制转换。最好的方法是使用 select

var fooList = intList.Select(x => (Foo)x).ToList();

关于c# - 为什么这个转换操作失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4084927/

相关文章:

c# - 如何删除罗斯林?

c# - 基于模板的 XML 到 CSV 转换

c++ - 当 short int[] 自动转换为 long int[] 时会发生什么?

c++ - 指向函数指针数组的指针

mongodb - 是否可以强制转换 MongoDB 查询?

c# - Xamarin ScrollView 应该跳到底部

c# - NHibernate HQL with isnull() 在哪里不起作用

c# - 显示部分用户控件的工具提示

c# - 在 Linq 表达式中使用可空类型

c# - Linq to 实体扩展方法内部查询 (EF6)