【问题标题】:Cast<int>.Cast<int?> applied on generic enum collection results in invalid cast exceptionCast<int>.Cast<int?> 应用于通用枚举集合会导致无效的强制转换异常
【发布时间】:2013-12-01 10:05:33
【问题描述】:
enum Gender { Male, Female }

var k = new[] { Gender.Male }.Cast<int>().ToList().Cast<int?>().ToList(); //alright

var p = new[] { Gender.Male }.Cast<int>().Cast<int?>().ToList(); //InvalidCastException

第二种情况的原因是什么?我知道我不能直接将盒装的enum 投射到int?,但我做了两个阶段的投射,即Cast&lt;int&gt;.Cast&lt;int?&gt;,这应该可以工作。

编辑:

考虑到以下作品,这令人惊讶:

object o = Gender.Male;
int i = (int)o; // so here the cast is not to an entirely different type, which works

【问题讨论】:

    标签: c# casting enums type-conversion


    【解决方案1】:

    好吧,我是来查原因的,还是很奇怪。我应该首先自己检查Cast&lt;T&gt; 的实现!

    Cast&lt;T&gt; 是这样实现的:

    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
    {
        IEnumerable<TResult> enumerable = source as IEnumerable<TResult>;
        if (enumerable != null)
        {
            return enumerable; // this is the culprit..
        }
        if (source == null)
        {
            throw Error.ArgumentNull("source");
        }
        return Enumerable.CastIterator<TResult>(source);
    }
    
    private static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
    {
        foreach (object current in source)
        {
            yield return (TResult)((object)current);
        }
        yield break;
    }
    

    现在问题在于 first Cast&lt;int&gt; 调用:

    new[] { Gender.Male }.Cast<int>()
    

    这里source as IEnumerable&lt;TResult&gt; sourcenew[] { Gender.Male }TResultint 在泛型方法中返回一个非空值(这基本上意味着(new[] { Gender.Male } 是一个@ 987654333@ 在通用上下文中),因此它返回相同的可枚举返回,即Gender[],并且在下一个Cast&lt;int?&gt; 调用中,执行实际的转换,即从Genderint? 失败。为什么会在一般情况下发生这种情况,catch it in this question

    【讨论】:

    • 这仍然留下问题...它不会失败如果扩展方法采用IEnumerable&lt;T&gt; 而不是IEnumerable。异常来自yield return 行,它尝试将Genderboxed 实例转换为int?。您可以轻松编写MyCast&lt;TIn, TResult&gt;(this IEnumerable&lt;TIn&gt; e)MyCastIterator&lt;TIn, TResult&gt;(IEnumerable&lt;T&gt; e),它会起作用,因为它不会装箱。为什么将盒装枚举类型转换为int? 失败,但将盒装int 转换为int? 成功,而将非盒装枚举类型转换为int? 也成功即使 它说 (object)current?
    • 不,我试过了,它就像我描述的那样工作。我只是不明白为什么。
    • @dialer 我同意你的观点 为什么要将装箱的枚举类型转换为 int?失败,但是将装箱的 int 转换为 int?成功了,一个非装箱的枚举类型和int?,它令人困惑。但我不同意将我原来的enum[] 传递给您的MyCast&lt;TIn, TResult&gt;(this IEnumerable&lt;TIn&gt; e) 使其成功。您确定,只要内部实现相同,调用enum[].MyCast&lt;enum, int&gt;().MyCast&lt;int, int?&gt;() 就可以正常工作吗?不,我不这么认为,这就是链接问题的意义所在。
    • 是的,这正是我要说的,这就是发生的区别:如您所知,(My)CastIterator 只会被调用一次,因为 return enumerable 在另一个函数中。但此时,非My 变体有一个IEnumerable,其中包含objects,其中框Genders,而My 变体有一个IEnumerable&lt;int&gt;,其中包含ints(最终被(object) 框住,但最终还是ints)。将object 转换为int? 是无效转换,但将int 转换为和int? 是成功的。然而,整个事情真的很奇怪。
    • 显然,这似乎是导致该行为的原因:(1) 您可以将盒装枚举转换为int。 (2) 您可以将已装箱的int 转换为int?。 (3) 您可以NON-boxed 枚举转换为int?。 (4) 您可以NOT将盒装枚举转换为int?
    【解决方案2】:

    这是由于延迟执行。后一个语句实际上试图将Gender.Male 转换为int?。相反,第一条语句实际上对int 执行强制转换操作,并在延迟执行以将它们强制转换为int? 之前获得List&lt;int&gt;;显然 intint? 已经定义了隐式转换。

    【讨论】:

    • 我认为根本不是这样。
    猜你喜欢
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    相关资源
    最近更新 更多