.net 为什么Linq会施展<;T>;定义隐式强制转换时操作失败?

.net 为什么Linq会施展<;T>;定义隐式强制转换时操作失败?,.net,linq,casting,.net,Linq,Casting,我创建了两个类,其中一个类之间有隐式强制转换: public class Class1 { public int Test1; } public class Class2 { public int Test2; public static implicit operator Class1(Class2 item) { return new Class1{Test1 = item.Test2}; } } 当我创建一种类型的新列表并尝试转

我创建了两个类,其中一个类之间有隐式强制转换:

public class Class1
{
    public int Test1;
}

public class Class2
{
    public int Test2;

    public static implicit operator Class1(Class2 item)
    {
        return new Class1{Test1 = item.Test2};
    }
}
当我创建一种类型的新列表并尝试转换为另一种类型时,它会失败,并出现InvalidCastException:

List<Class2> items = new List<Class2>{new Class2{Test2 = 9}};
foreach (Class1 item in items.Cast<Class1>())
{
    Console.WriteLine(item.Test1);
}

为什么在使用cast时不调用隐式cast?

因为,通过Reflector查看代码时,cast不会尝试使用任何隐式cast操作符(LINQ cast代码针对各种特殊情况进行了大量优化,但没有朝着这个方向进行任何优化)(因为许多.NET语言不会这样做)

在不考虑反射和其他因素的情况下,泛型不提供任何开箱即用的方法来考虑这些额外的东西


编辑:一般来说,更复杂的工具(如隐式/显式、相等运算符等)通常不会由LINQ这样的通用工具处理。

感谢我将在某个地方使用这个确切的例子。你为我节省了一大堆时间。作为问题的可能解决方案,您可以改用ConvertAll,如下所示:

foreach (Class1 item in items.ConvertAll<Class1>((i) => (Class1)i))
{
     Console.WriteLine(item.Test1);
}
foreach(items.ConvertAll中的Class1项((i)=>(Class1)i))
{
控制台写入线(第1项);
}
编辑:或者,如果您想更明确地说明强制转换是隐式的,那么这也可以:

foreach (Class1 item in items.ConvertAll<Class1>(i => i))
{
     Console.WriteLine(item.Test1);
}
foreach(items.ConvertAll中的Class1项(i=>i))
{
控制台写入线(第1项);
}

如果您确实需要这种转换,可以在此处使用一些linq'ing:

List items = new List{new Class2{Test2 = 9}}; foreach (Class1 item in (from x in items select (Class1)x)) { Console.WriteLine(item.Test1); } 列表项=新列表{newclass2{Test2=9}; foreach(类别1项输入(从项目中的x选择(类别1)x)) { 控制台写入线(第1项); }
如果需要,您还可以使用此选项进行转换转换:

public static IEnumerable<TDest> CastAll<TItem, TDest>(this IEnumerable<TItem> items)
{
 var p = Expression.Parameter(typeof(TItem), "i");
 var c = Expression.Convert(p, typeof(TDest));
 var ex = Expression.Lambda<Func<TItem, TDest>>(c, p).Compile();

 foreach (var item in items)
 {
    yield return ex(item);
 }
}
公共静态IEnumerable CastAll(此IEnumerable项)
{
var p=表达式参数(typeof(TItem),“i”);
var c=表达式.Convert(p,typeof(TDest));
var ex=Expression.Lambda(c,p).Compile();
foreach(项目中的var项目)
{
收益率收益率(项目);
}
}

interest中,您可能会删除这种情况下的显式强制转换,这将清楚地表明强制转换是隐式的?在not中,您可以使用Select()确定,您将赢得。。。您无法完全删除它,因为ConvertAll需要向其传递一个委托。但是,默认的i=>i是有效的。虽然现在可读性开始丧失,因此我更喜欢我的第一个解决方案,或者只是(i=>(Class1)i)告诉读者更多关于正在发生的事情。我想保留集合,我返回了一个IEnumerable,但没有将其转换为列表,所以我最终做了以下操作:返回项。选择(i=>(Class1)i);我知道我在问题中没有提到这一点,但我想在我的真实代码中这样做。通过使用这种方法,我不必担心创建一个单独的列表。嗨,Ryan,很高兴你很高兴并且有了结果。我建议优先使用ConvertAll来选择,就像David所做的那样,因为它可以更清楚地向读者传达代码试图实现的目标。(请注意,您的方法体将读取“returnitems.ConvertAll(i=>i);”)而不是以列表开头,而是以IEnumerable开头。我不得不将您的建议修改为:“return items.ToList().ConvertAll(I=>I);”在我的情况下,这似乎是不必要的,尽管我可以从其他人身上看到好处。我使用它的地方也不应该引起任何混淆——将数据集生成的类转换为在整个项目中使用的独立类。不过,我很重视其他观点,所以谢谢你的意见!
public static IEnumerable<TDest> CastAll<TItem, TDest>(this IEnumerable<TItem> items)
{
 var p = Expression.Parameter(typeof(TItem), "i");
 var c = Expression.Convert(p, typeof(TDest));
 var ex = Expression.Lambda<Func<TItem, TDest>>(c, p).Compile();

 foreach (var item in items)
 {
    yield return ex(item);
 }
}