C# .NET Casting 通用列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/674715/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 12:56:11  来源:igfitidea点击:

.NET Casting Generic List

c#.netgenericscasting

提问by Josh

Can someone explain to me why in .NET 2.0 if I have an interface, IPackableand a class that implements that interface OrderItem, when I have a method that takes in a List<IPackable>, passing in a list of List<OrderItem>does not work?

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

Does anyone know how I could accomplish this functionality?

有谁知道我如何完成这个功能?

Code:

代码:

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;
   }
}

The following code does not work.

以下代码不起作用。

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

采纳答案by JMD

The feature is called covariance/contravariance and will be supported in c# 4.0. You can read about it here: http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

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

回答by mqp

JMD's answer is correct. For a workaround, you can try this:

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

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

Or, if the list must be strongly typed as OrderItems, then this (3.0 only, sorry):

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

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

回答by mqp

JMD is half correct. In fact, it's absolutely incorrect to say that we will be able to cast a generic list with C# 4.0. It's true that covariance and contravariance will be supported in C# 4.0 but it will only works with interface and delegate and there will have a lot of constraints. Therefore, it won't work with List.

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

The reason is really simple.

原因其实很简单。

If B is a subclass of A, we cannot say that List<B>is a subclass of List<A>.

如果 B 是 A 的子类,我们不能说它List<B>是 的子类List<A>

And here's why.

这就是原因。

List<A>exposes some covariances methods (returning a value) and some contravariances methods (accepting a value as a parameter).

List<A>公开一些协方差方法(返回一个值)和一些逆变方法(接受一个值作为参数)。

e.g.

例如

  • List<A>exposes Add(A);
  • List<B>exposes Add(B);
  • List<A>暴露 Add(A);
  • List<B>暴露 Add(B);

If List<B>inherits from List<A>...than you would be able to do List<B>.Add(A);

如果List<B>继承自List<A>...比你能做的List<B>.Add(A);

Therefore, you would loose all type safety of generics.

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

回答by Zarigani

Actually, you can solve this by making GetForShipWeight a generic function:

实际上,您可以通过将 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);
}

回答by Bigjim

An alternative solution that also works for .NET 3.5

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

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