Sho*_*kie 7 c# c++ java covariance contravariance
我已经阅读了以下有关逆差异的帖子和Lasse V. Karlsen的回答:
理解C#中的Covariant和Contravariant接口
即使我理解这个概念,我也不明白为什么它有用.例如,为什么有人会制作一个只读列表(如帖子中所示List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>)
我也知道,重写方法的参数可能是矛盾的(从概念上讲.据我所知,这在C#,Java和C++中没有使用).这有什么例子才有意义?
我会欣赏一些简单的现实世界的例子.
(我认为这个问题更多的是关于协方差而不是逆变,因为引用的例子与协方差有关。)
List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
脱离上下文,这有点误导。在您引用的示例中,作者意图传达这样的想法:从技术上讲,如果 theList<Fish>实际上引用了 a,List<Animal>则向其添加 a是Fish安全的。
但当然,这也会让你添加一个Cow- 这显然是错误的。
因此编译器不允许您将List<Animal>引用分配给List<Fish>引用。
那么什么时候这才真正安全且有用呢?
如果集合不能被修改,那么这是一个安全的赋值。在 C# 中,anIEnumerable<T>可以表示不可修改的集合。
所以你可以安全地执行此操作:
IEnumerable<Animal> animals = GetAccessToFishes(); // for some reason, returns List<Animal>
因为不可能将非 Fish 添加到animals. 它没有方法允许您这样做。
那么这什么时候有用呢?
每当您想要访问集合的某些通用方法或属性(其中可以包含从基类派生的一种或多种类型的项目)时,这非常有用。
例如,您可能有一个代表超市不同类别库存的层次结构。
假设基类StockItem具有属性double SalePrice。
还假设您有一个方法,Shopper.Basket()它返回IEnumerable<StockItem>代表购物者购物篮中的商品的 。篮子中的物品可以是源自 的任何具体类型StockItem。
在这种情况下,您可以添加购物篮中所有商品的价格(我是手写的,没有使用 Linq 来弄清楚发生了什么。当然会使用真正的代码IEnumerable.Sum()):
IEnumerable<StockItem> itemsInBasket = shopper.Basket;
double totalCost = 0.0;
foreach (var item in itemsInBasket)
totalCost += item.SalePrice;
Run Code Online (Sandbox Code Playgroud)
逆变
逆变的一个使用示例是,当您想要通过基类类型对项目或项目集合应用某些操作时,即使您有派生类型也是如此。
例如,您可以有一个方法,按如下顺序对每个项目应用操作StockItem:
void ApplyToStockItems(IEnumerable<StockItem> items, Action<StockItem> action)
{
foreach (var item in items)
action(item);
}
Run Code Online (Sandbox Code Playgroud)
使用该StockItem示例,我们假设它有一个Print()方法,您可以使用该方法将其打印到收银机收据上。您可以调用然后像这样使用它:
Action<StockItem> printItem = item => { item.Print(); }
ApplyToStockItems(shopper.Basket, printItem);
Run Code Online (Sandbox Code Playgroud)
在此示例中,购物篮中的商品类型可能是Fruit、、等等。但因为它们都派生自,所以该代码适用于所有它们。ElectronicsClothingStockItem
希望这种代码的用途是清楚的!这与 Linq 中许多方法的工作方式非常相似。
| 归档时间: |
|
| 查看次数: |
479 次 |
| 最近记录: |