【问题标题】:.NET Casting Generic List.NET 转换通用列表
【发布时间】:2010-10-15 01:17:34
【问题描述】:

如果我有一个接口IPackable 和一个实现该接口OrderItem 的类,当我有一个接受List<IPackable> 的方法时,有人可以向我解释为什么在.NET 2.0 中,传入一个列表List<OrderItem> 不起作用?

有谁知道我如何实现这个功能?

代码:

public interface IPackable {
        double Weight{ get; }
}

public class OrderItem : IPackable


public List<IShipMethod> GetForShipWeight(List<IPackable> packages) {
   double totalWeight = 0;
   foreach (IPackable package in packages) {
        totalWeight += package.Weight;
   }
}

以下代码不起作用。

List<OrderItem> orderItems = new List<OrderItem>();
List<IShipMethod> shipMethods = GetForShipWeight(orderItems);

【问题讨论】:

  • 请发布相关代码以及您遇到的具体问题(构建错误、运行时错误等)。

标签: c# .net generics casting


【解决方案1】:

该功能称为协变/逆变,将在 c# 4.0 中得到支持。你可以在这里阅读:http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

【讨论】:

  • 文章似乎移动了。请看下面的示例,Cast 类位于 System.Linq 命名空间中,仅供参考。
【解决方案2】:

JMD 的回答是正确的。对于解决方法,您可以尝试以下方法:

List<IPackable> orderItems = new List<IPackable>();
List<IShipMethod> shipMethods = GetForShipWeight(orderItems);

或者,如果列表必须强类型为 OrderItems,那么这个(仅限 3.0,抱歉):

List<IShipMethod> shipMethods =
    GetForShipWeight(orderItems.Cast<IPackable>().ToList());

【讨论】:

    【解决方案3】:

    JMD 说对了一半。事实上,说我们将能够使用 C# 4.0 转换通用列表是绝对不正确的。确实,C# 4.0 将支持协变和逆变,但它只适用于接口和委托,并且会有很多约束。因此,它不适用于List

    原因很简单。

    如果 B 是 A 的子类,我们不能说 List&lt;B&gt;List&lt;A&gt; 的子类。

    这就是为什么。

    List&lt;A&gt; 公开了一些协方差方法(返回一个值)和一些逆变方法(接受一个值作为参数)。

    例如

    • List&lt;A&gt; 暴露 Add(A);
    • List&lt;B&gt; 暴露 Add(B);

    如果List&lt;B&gt; 继承自List&lt;A&gt;...那么您将能够做到List&lt;B&gt;.Add(A);

    因此,您将失去泛型的所有类型安全性。

    【讨论】:

      【解决方案4】:

      实际上,您可以通过将 GetForShipWeight 设为通用函数来解决此问题:

      public interface IPackable { double Weight { get; } }
      public interface IShipMethod { }
      
      public class OrderItem : IPackable { }
      
      public List<IShipMethod> GetForShipWeight<T>(List<T> packages) where T : IPackable
      {
          List<IShipMethod> ship = new List<IShipMethod>();
          foreach (IPackable package in packages)
          {
              // Do something with packages to determine list of shipping methods
          }
          return ship;
      }
      public void Test()
      {
          List<OrderItem> orderItems = new List<OrderItem>();
          // Now compiles...
          List<IShipMethod> shipMethods = GetForShipWeight(orderItems);
      }
      

      【讨论】:

        【解决方案5】:

        也适用于 .NET 3.5 的替代解决方案

        List<IShipMethod> shipMethods = GetForShipWeight(orderItems).ConvertAll(sm => sm as IShipMethod);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-03-22
          • 2012-02-19
          • 2013-08-24
          • 2010-11-02
          • 2010-10-18
          • 2010-10-07
          • 1970-01-01
          相关资源
          最近更新 更多