- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我已阅读以下关于反方差的帖子和 Lasse V. Karlsen 的回答:
Understanding Covariant and Contravariant interfaces in C#
虽然我理解这个概念,但我不明白它为什么有用。例如,为什么有人会制作一个只读列表(如帖子中:List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
)
我也知道覆盖方法的参数可以是反变的(概念上。据我所知,这在 C#、Java 和 C++ 中没有使用)。有哪些例子表明这是有道理的?
我会很感激一些简单的现实世界的例子。
最佳答案
(我认为这个问题更多的是关于协方差而不是逆变,因为引用的例子与协方差有关。)
List<Fish> fishes = GetAccessToFishes(); // for some reason, returns List<Animal>
断章取义,这有点误导。在您引用的示例中,作者打算从技术上传达这样的想法,如果 List<Fish>
实际上是在引用 List<Animal>
添加一个 Fish
将是安全的给它。
当然,这也可以让您添加 Cow
对它 - 这显然是错误的。
因此编译器不允许您分配 List<Animal>
引用 List<Fish>
引用。
那么什么时候这才是真正安全且有用的呢?
如果集合不能被修改,这是一个安全的赋值。在 C# 中,一个 IEnumerable<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;
逆变
逆变的一个例子是当你想通过基类类型对一个项目或项目集合应用一些 Action 时,即使你有一个派生类型。
例如,您可以使用一种方法对 StockItem
序列中的每个项目应用操作像这样:
void ApplyToStockItems(IEnumerable<StockItem> items, Action<StockItem> action)
{
foreach (var item in items)
action(item);
}
使用 StockItem
例如,假设它有一个 Print()
您可以使用该方法将其打印到收银台收据上。你可以像这样调用然后使用它:
Action<StockItem> printItem = item => { item.Print(); }
ApplyToStockItems(shopper.Basket, printItem);
在此示例中,购物篮中的商品类型可能是 Fruit
, Electronics
, Clothing
等等。但是因为它们都来自 StockItem
,代码适用于所有这些。
希望这种代码的用途是明确的!这与 Linq 中许多方法的工作方式非常相似。
关于c# - 反方差的常见编程用途是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19475577/
我的应用程序上有一个抽屉式菜单,它在桌面上运行良好,但在任何移动设备上我都看到一个丑陋的卡顿。 在 header 中,我有一个 bool 值,在单击汉堡包时将其设置为 true/false,这会将 o
在CLRS书中,自上而下的heapify构建堆的复杂度为O(n)。也可以通过反复调用插入来建立堆,其最坏情况下的复杂度为nlg(n)。 我的问题是:对于后一种方法性能较差的原因,是否有任何见解? 我问
我在所有层和输出上使用 sigmoid,得到的最终错误率为 0.00012,但是当我使用理论上更好的 Relu 时,我得到了最差的结果。谁能解释为什么会发生这种情况?我正在使用一个非常简单的 2 层实
我想计算有多少人(百分比)在我的测试中表现比我差。 这是我想要的结果: student | vak | resultaat | percentielscore ---------+-------
令人惊讶的是,使用 PLINQ 并没有在我创建的一个小测试用例上产生好处;事实上,它比通常的 LINQ 还要糟糕。 测试代码如下: int repeatedCount = 10000000;
我正在开发一个高度基于 map 的应用程序,并且我正在使用 MBXMapKit 框架(基于 MapKit 构建)以便在我的 MapView 中显示自定义 Mapbox map 图 block 而不是默
这个问题在这里已经有了答案: Is it always better to use 'DbContext' instead of 'ObjectContext'? (1 个回答) 关闭 9 年前。
我正在尝试使用 FFmpeg 进行一些复杂的视频转码(例如连接多个文件)。为此,我一直在尝试使用 filter_complex,但我注意到我之前使用普通视频过滤器看到的质量略有下降。 为了仔细检查,我
我是 R 中并行计算的新手,想使用并行包来加速我的计算(这比下面的示例更复杂)。但是,与通常的 lapply 函数相比,使用 mclapply 函数的计算时间更长。 我在我的笔记本电脑上安装了一个全新
我正在尝试使用 BERT 解决文档排名问题。我的任务很简单。我必须对输入文档进行相似度排名。这里唯一的问题是我没有标签——所以它更像是一个定性分析。 我正在尝试一系列文档表示技术——主要是 word2
如何计算两点的差?例如:(5,7) - (2,3) = (3,4) using point = boost::geometry::model::point point p1 (2, 3); point
我是 ARKit 的新手,在检查了一些示例代码后,如 https://developer.apple.com/sample-code/wwdc/2017/PlacingObjects.zip我想知道是
社区。 我正在编写一些机器学习代码,将一些数据分类。 我尝试了不同的方法,但是当我使用SVM时,我遇到了这个问题。 我有一组简单的数据(3 个类别,6 个特征),当我使用具有固定参数(C=10、gam
我只是在查看不同问题的答案以了解更多信息。我看到一个answer这表示在 php 中编写 是不好的做法 for($i=0;$i
我正在编写一个界面,我必须在其中启动 4 个 http 请求才能获取一些信息。 我用两种方式实现了接口(interface): 使用顺序 file_get_contents。 使用多 curl 。 我
我想用随机数来愚弄一下,如果 haskell 中的随机生成器是否均匀分布,因此我在几次尝试后写了下面的程序(生成的列表导致堆栈溢出)。 module Main where import System.
我在 Tensorflow 中构建了一个 LSTM 分类器(使用 Python),现在我正在做一系列基准测试来衡量执行性能。基准测试代码加载在训练期间保存的模型并针对大量输入执行它。我有一个 Pyth
不久前,我重构了单元格渲染器组件以实现性能提升(我有一个巨大的表格)。我从功能性无状态组件重构为 PureComponent。例如: import React from 'react'; import
当我改变缓冲区的大小时,我得到了无法从 BufferedReader 解释的奇怪结果。 我曾强烈期望性能会随着缓冲区大小的增加而逐渐增加, yield 递减设置相当快,此后性能或多或少会持平。但看起来
我正在尝试为 1000 个正面+负面标签的 IMDB 评论 (txt_sentoken) 和 Java 的 weka API 构建一个基于朴素贝叶斯的分类器。 由于我不知道 StringToWordV
我是一名优秀的程序员,十分优秀!