C# 中的协变和逆变

2024-06-19

首先我要说的是,我是一名正在学习 C# 编程的 Java 开发人员。因此,我会将我所知道的与我正在学习的进行比较。

我已经使用 C# 泛型几个小时了,我已经能够在 C# 中重现我在 Java 中知道的相同内容,除了几个使用协变和逆变的示例。我正在读的书在这个主题上不是很好。我当然会在网上寻找更多信息,但在我这样做的同时,也许您可​​以帮助我找到以下 Java 代码的 C# 实现。

一个例子抵得上一千个字,我希望通过查看一个好的代码示例我能够更快地理解它。

协方差

在Java中我可以做这样的事情:

public static double sum(List<? extends Number> numbers) {
    double summation = 0.0;
    for(Number number : numbers){
        summation += number.doubleValue();
    }
    return summation;
}

我可以按如下方式使用此代码:

List<Integer> myInts = asList(1,2,3,4,5);
List<Double> myDoubles = asList(3.14, 5.5, 78.9);
List<Long> myLongs = asList(1L, 2L, 3L);

double result = 0.0;
result = sum(myInts);
result = sum(myDoubles)
result = sum(myLongs);

现在我确实发现 C# 仅在接口上支持协变/逆变,只要它们已明确声明这样做(out/in)即可。我认为我无法重现这种情况,因为我找不到所有数字的共同祖先,但我相信如果存在共同祖先,我可以使用 IEnumerable 来实现这样的事情。由于 IEnumerable 是协变类型。正确的?

关于如何实施上面的列表有什么想法吗?只要指出我正确的方向即可。所有数字类型是否有共同的祖先?

逆变

我尝试的逆变示例如下。在 Java 中,我可以这样做将一个列表复制到另一个列表中。

public static void copy(List<? extends Number> source, List<? super Number> destiny){
    for(Number number : source) {
       destiny.add(number);
    }
}

然后我可以将它与逆变类型一起使用,如下所示:

List<Object> anything = new ArrayList<Object>();
List<Integer> myInts = asList(1,2,3,4,5);
copy(myInts, anything);

我尝试在 C# 中实现这一点的基本问题是,我无法找到同时协变和逆变的接口,就像上面示例中的 List 的情况一样。也许可以用 C# 中的两个不同的接口来完成。

关于如何实施这个有什么想法吗?

非常感谢大家提供的任何答案。我很确定我会从您提供的任何示例中学到很多东西。


我不会直接回答您的问题,而是会回答一些略有不同的问题:

C# 是否有办法泛化支持算术运算符的类型?

不容易,不。如果有能力制作一个Sum<T>可以添加整数、双精度数、矩阵、复数、四元数...等等的方法。尽管这是一个相当频繁请求的功能,但它也是一个很大的功能,并且它在优先级列表上的位置从未足够高,不足以证明其包含在该语言中是合理的。我个人喜欢它,但你不应该期望它出现在 C# 5 中。也许在该语言的假设的未来版本中。

Java 的“调用点”协变/逆变和 C# 的“声明点”协变/逆变有什么区别?

当然,实现层面上的根本区别在于,实际上,Java 泛型是通过擦除来实现的;尽管您可以获得泛型类型的良好语法和编译时类型检查的好处,但您不一定会获得 C# 中的性能优势或运行时类型系统集成优势。

但这实际上更多的是一个实现细节。从我的角度来看,更有趣的区别是 Java 的方差规则是强制执行的locally并强制执行 C# 的方差规则globally.

也就是说:某些变体转换是危险的,因为它们意味着某些非类型安全操作将不会被编译器捕获。经典的例子是:

  • 老虎是哺乳动物。
  • X 的列表在 X 中是协变的。(假设。)
  • 因此,老虎列表就是哺乳动物列表。
  • 哺乳动物列表中可以插入长颈鹿。
  • 因此,您可以将长颈鹿插入到老虎列表中。

这显然违反了类型安全以及长颈鹿的安全。

C# 和 Java 使用两种不同的技术来防止这种类型安全违规。 C# 说当I<T>声明接口,如果声明为协变则接口中不能有任何方法接受 T。如果没有方法将 T 插入到列表中,那么您永远不会将长颈鹿插入到老虎列表中,因为没有方法插入anything.

相比之下,Java 表示在这个本地站点,我们可以协变地对待类型,并且我们承诺不会在这里调用任何可能违反类型安全的方法。

我对 Java 的功能没有足够的经验,无法说哪个在什么情况下“更好”。 Java 技术当然很有趣。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 中的协变和逆变 的相关文章

随机推荐

  • 使用服务总线触发器在 Azure 函数中参考配置中的主题和订阅名称

    我有一个带有服务总线主题触发器的 Azure 服务总线 我的功能看起来像这样 FunctionName SbListener public static async Task Run ServiceBusTrigger test topic
  • Nodemailer:从未收到问候语

    当尝试使用 Nodemailer 在 Node 内发送电子邮件时 https github com nodemailer nodemailer https github com nodemailer nodemailer 调用sendMai
  • 切换图片框可见性 C#

    为什么图片框控件的可见性属性在这里不起作用 我最初将它们设置为 false 以便在屏幕加载时它们不可见 但后来我想切换这个 我已完成以下操作 但似乎不起作用 这是一个 Windows 窗体应用程序 private void Action w
  • 使用会话在 Django 中将文件从一个视图传递到另一个视图

    我当前的工作项目要求我允许用户上传各种格式的文件 目前仅处理 CSV 格式 然后使用包含的数据来绘制图表Pandas http pandas pydata org 图书馆 我决定将图形渲染到模板的最简单方法是为图形创建特定视图 然后将图像从
  • Swift 相当于 Objective-C FourCharCode 单引号文字(例如 'TEXT')

    我正在尝试在 Swift 中复制一些 Objective C cocoa 一切都很好 直到我遇到以下情况 Set a new type and creator unsigned long type TEXT unsigned long cr
  • Python 在哪些系统上不使用 IEEE-754 双精度浮点数

    Python 对 IEEE 754 浮点运算进行了各种引用 但不保证1 https docs python org 3 tutorial floatingpoint html 2 https pythondev readthedocs io
  • 创建多个 git 分支的联合分支

    我希望能够在现有分支之上分层其他分支 并独立修改这些分支 这很有用 例如 允许将各个子项目的二进制文件统一到同一个项目中bin目录 一般来说 给定的文件仅存在于一层中 理想情况下 我想我会使用 unionfs 来完成此任务 但它必须以某种方
  • 方向改变时的类转换异常 (Android)

    我有一个由选项卡活动托管的活动 当我更改屏幕方向时 我的应用程序崩溃了 02 14 21 01 35 825 E AndroidRuntime 9424 java lang RuntimeException Unable to start
  • 动态选取框文本

    是否可以将列表视图的 java 编码中的文本添加到 Android 中的选取框滚动中 如果可以 请告诉我如何做 如果需要 我将发布使用的代码 这是列表视图使用的 XML 如下
  • 在 Spring Data JPA 中删除同一事务后插入

    使用 Spring Data JPA 我在同一事务内有下一个流程 REQUIRES NEW 使用此 Spring Data JPA 存储库方法删除一组用户的预测 Query value DELETE FROM TRespuestaUsuar
  • 如何以编程方式设置设备(UI)方向?

    希望屏幕 UI 上的所有内容都能够从横向左向右旋转 反之亦然 我该怎么做呢 这是私人的吗 我知道 BOOL shouldAutorotateToInterfaceOrientation UIInterfaceOrientation inte
  • Notepad++保存时可以自动上传本地文件到服务器吗?

    我使用 Notepad 及其 NppFTP 插件 我需要保持本地副本最新 因此我编辑本地文件然后将它们上传到服务器 我想知道是否有一种方法可以让 Notepad 在保存文件后立即自动将文件上传到服务器 而无需按另一个按钮 我愿意使用其他 F
  • 处理过时的 NSURL 书签的正确方法是什么?

    从安全范围的书签解析 NSURL 时 如果用户已重命名或移动该文件或文件夹 则该书签将过时 苹果的文档对于陈旧性有这样的描述 isStale 返回时 如果是 则书签数据已过时 你的应用程序应该 使用返回的 URL 创建一个新书签并用它代替
  • 按字符分割字符串

    scala 有一个标准的分割字符串的方法StringOps split 但它的行为有点让我惊讶 演示一下 使用快捷便利功能 def sp str String str split toList 以下表达式全部计算结果为 true sp Li
  • 使用 python 脚本更改 shell 中的工作目录

    我想实现一个用户态命令 它将采用其参数之一 路径 并将目录更改为该目录 程序完成后 我希望 shell 位于该目录中 所以我想实施cd命令 但需要外部程序 可以在 python 脚本中完成还是我必须编写 bash 包装器 Example t
  • BlackBerry SQLite:将一个 SQLite 数据库连接到另一个

    我正在尝试使用 SQLite 将一个 SQLite 数据库附加到 BlackBerry 上的另一个数据库附加数据库 http www sqlite org lang attach html命令 Database d1 d2 Statemen
  • Java 泛型:如何为泛型类型指定类类型?

    我有一个 POJO 指定为 MyClass u where U是泛型类型参数 我正在尝试编写一个接受类引用的实用方法Class u
  • VS 2010 Web应用程序中的ASP.NET Web Api CRUD操作

    我尝试在 VS 2010 Web 应用程序中进行 ASP NET Web Api CRUD 操作 但为什么结果没有从源表返回所有整行 这是我的代码 路线 Globax asax protected void Application Star
  • WebClient读取错误页面的内容

    我有一个加载页面内容的应用程序 我使用 WebClient 类 即使服务器返回 404 500 等错误 我也需要检索内容 我需要这样的东西 WebClient wc new WebClient string pageContent try
  • C# 中的协变和逆变

    首先我要说的是 我是一名正在学习 C 编程的 Java 开发人员 因此 我会将我所知道的与我正在学习的进行比较 我已经使用 C 泛型几个小时了 我已经能够在 C 中重现我在 Java 中知道的相同内容 除了几个使用协变和逆变的示例 我正在读