C# 为什么Enumerable.Cast不使用我的转换运算符?

C# 为什么Enumerable.Cast不使用我的转换运算符?,c#,linq,C#,Linq,使用此类型: class Foo { public static implicit operator int(Foo obj) { return 5; } } var test=new[] { new Foo() }; 以下工作与预期相符 var ok=test.Select(x => (int)x).ToList(); 但是使用Cast失败了,出现了一个InvalidCastException-为什么 var fail=test.Cast<int>(

使用此类型:

class Foo
{
  public static implicit operator int(Foo obj)
  {
    return 5;
  }
}

var test=new[] { new Foo() };
以下工作与预期相符

var ok=test.Select(x => (int)x).ToList();
但是使用Cast失败了,出现了一个InvalidCastException-为什么

var fail=test.Cast<int>().ToList();

Enumerable.Cast的文档实际上在这方面有点含糊,并讨论了转换和转换。但是,它确实指出,如果一个元素不能转换为类型TResult,这个方法将抛出一个异常,并且您的类Foo不能转换为int,但可以使用转换语法进行转换。后者是一个方法调用

通常情况下,演员阵容和打字工作类似于“原样”,若你们写了:

var foo = new Foo()
var bar = foo is int;

酒吧是假的。虽然MSDN上的文档并不完全相同,但Cast似乎与此一致。并在is运算符返回false时失败。有一种特殊情况不会出现这种情况,那就是如果序列中的值为null,并且T是引用类型

请阅读Jon Skeet关于重新实现Linq EduLinq的博客,具体来说,他在博客中说:

值得注意的是,从.NET3.5SP1开始,Cast和OfType只执行引用和取消装箱转换。它们不会将装箱的int转换为long,也不会执行用户定义的转换。基本上,它们遵循与从对象转换为泛型类型参数相同的规则。这对实现非常方便


强制转换运算符纯粹是C编译器级别的特性,运行时对它们一无所知,因此没有简单的方法通过泛型强制转换方法实现这一点。一种方法是执行运行时代码生成:


    public static class Converter<TSource, TResult>
    {
        static Converter()
        {
            var sourceParameter = Expression.Parameter(typeof(TSource));
            var conversionExpression = Expression.Lambda<Func<TSource, TResult>>(
                Expression.Convert(sourceParameter, typeof(TResult)),
                sourceParameter);

            Instance = conversionExpression.Compile();
        }

        public static Func<TSource, TResult> Instance
        {
            get;
            private set;
        }
    }

    public static class EnumerableEx
    {
        public static IEnumerable<TResult> Cast<TSource, TResult>(this IEnumerable<TSource> source)
        {
            return source.Select(Converter<TSource, TResult>.Instance);
        }
    }
但是,您将失去编译时检查:


var test = new[] { new Foo() };
var ok = test.Cast<Foo, int>().ToList(); // compiles and works ok
var error = test.Cast<Foo, double>().ToList(); // compiles but fails at run-time

另一种方法是像中一样使用反射,但这对从int到long这样的内置转换不起作用。

看看这是否是您的问题:我尝试了这个,您的代码示例根本不起作用,在ok行中失败,带有InvalidCastException,您确定这个示例应该起作用吗?@matt-是的,谢谢您的链接!以前没见过。@David它在我.net4上运行