【问题标题】:Why can't I use LINQ to Objects when my class implements IEnumerable<T> multiple times?当我的类多次实现 IEnumerable<T> 时,为什么我不能使用 LINQ to Objects?
【发布时间】:2011-06-24 19:09:52
【问题描述】:

我有一个有趣的问题,即一个类继承自一个实现 IEnumerable 的类,但我也希望该类为不同的类型实现 IEnumerable。除了 IEnumerable 扩展方法外,一切正常,这意味着我不能在默认情况下对对象执行任何 LINQ,而不必总是先进行强制转换。除了不断投射,还有人有什么想法吗?

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqTesting
{
    public class Trucks<T> : Vehicles, IEnumerable<Truck>
    {    
        public Trucks()
        {    
            // Does Compile
            var a = ((IEnumerable<Truck>)this).FirstOrDefault();
            // Doesn't Compile, Linq.FirstOrDefault not found
            var b = this.FirstOrDefault();
        }    

        public new IEnumerator<Truck> GetEnumerator() { throw new NotImplementedException(); }
    }    

    public class Vehicles : IEnumerable<Vehicle>
    {    
        public IEnumerator<Vehicle> GetEnumerator() { throw new NotImplementedException(); }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
    }    

    public class Vehicle { }

    public class Truck : Vehicle { }
}     

【问题讨论】:

  • 你的 Truck 对象不是继承了两个 IEnumerable 类型吗?您如何期望编译器找出您要使用的可枚举类型,尝试向上转换为您想要的类型,然后选择 FirstOrDefault

标签: c# ienumerable linq-to-objects


【解决方案1】:

其实可以,但是不能利用泛型类型推断,因为你的类实现了两个不同类型的IEnumerable&lt;T&gt;,编译器不知道你要使用哪种类型。

您可以直接指定它,例如:

var b = this.FirstOrDefault<Truck>();

【讨论】:

  • 这确实是我所缺少的。这很令人困惑,因为智能感知会弹出显示方法,但它也会在同一行显示错误,因为编译器不能再利用泛型类型推断。
【解决方案2】:

将您的代码更改为:

public class Trucks : Vehicles<Truck>
{    
}    

public class Vehicles<T> : IEnumerable<T>
    where T : Vehicle
{    
}    

public class Vehicle { }

public class Truck : Vehicle { }

【讨论】:

  • 不幸的是,我无法访问基类代码,但这将是正确的解决方案。我得看看能不能做出这样的改变。谢谢!
【解决方案3】:

多次实现 IEnumerable 会使编译器感到困惑,为此应该考虑使用哪个 IEnumerable。

IEnumerable<Vehicle> or IEnumerable<Truck>?

this.FirstOrDefault<Truck>() might compile. 

【讨论】:

    【解决方案4】:

    看起来你有点卡住了。这是减少打字的建议。您可以为一些常用的 IEnumerable 类型创建扩展方法。

    var a = myList.AsTruckEnumerable().FirstOrDefault();
    
    public static partial class Extensions
    {
      public static IEnumerable<Truck> AsTruckEnumerable (this IEnumerable<Truck> trucks)
      {
         return trucks;
      }
    }
    
    public class Trucks<T> : Vehicles, IEnumerable<Truck>
    {    
       public Trucks()
       {    
          // Does Compile
          var a = ((IEnumerable<Truck>)this).FirstOrDefault();
    
          // Does compile
          var b = this.AsTruckEnumerable().FirstOrDefault();
          // Doesn't Compile, Linq.FirstOrDefault not found
          //var b = this.FirstOrDefault();
       }    
    
       public new IEnumerator<Truck> GetEnumerator() { throw new NotImplementedException(); } 
    }    
    

    【讨论】:

      【解决方案5】:

      public new IEnumerator GetEnumerator()

      该行中的 new 关键字隐藏从 Vehicle 类继承的 GetEnumerator() 方法。我不确定这是否可行,但不妨试试explicit interface implementation

      【讨论】:

      • 对某些接口使用显式接口实现而对其他接口使用隐式实现不会改变扩展方法的分辨率。仅当您直接调用 GetEnumerator() 时才有帮助,所以这没有帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-27
      • 1970-01-01
      • 2011-04-04
      • 2011-07-29
      • 2015-09-20
      • 2010-09-21
      相关资源
      最近更新 更多