无法将值类型数组转换为 params object[]

2023-11-21

如果 C# 可以将 int 转换为对象,为什么不能将 int[] 转换为 object[]?

简单程序示例:

void Main()
{
    var a = new String[]{"0", "1"};
    var b = new int[]{0, 1};

    AssertMoreThan1(a); // No Exception
    AssertMoreThan1(b); // Exception
}

static void AssertMoreThan1(params object[] v){
    if(v.Length == 1){
        throw new Exception("Too Few Parameters");
    }
}

如果 C# 可以将 int 转换为对象,为什么不能将 int[] 转换为 object[]?

您的问题也可以表述为“什么是协方差C# 中数组转换的规则?”

它们有点棘手,并且以几种有趣和不幸的方式被破坏。

首先,我们应该清楚地说明“协方差”的含义。协方差是一个属性mapping保留了一个关系。这里的映射是“T 到 T 的数组”。这关系是“可以隐式转换”。例如:

Giraffe可以隐式转换为Mammal.

这是两种类型之间的关系。现在将映射应用到关系的两侧:

Giraffe[]可以转换为Mammal[].

如果第一个陈述的真实性总是蕴含第二个陈述的真实性——也就是说,如果映射果酱关系的真实性——那么映射被称为“协变”。

作为简写,我们不说“从 T 到 T 的数组的映射是隐式转换关系上的协变映射”,而是只说“数组是协变的”,并希望其余部分可以从上下文中理解。

好的,现在我们已经有了定义:数组带有引用类型元素在 C# 中是协变的。可悲的是,这是破坏协方差的:

class Mammal {}
class Giraffe : Mammal {}
class Tiger : Mammal {}
...
Mammal[] mammals = new Giraffe[1];  

这是完全合法的,因为引用类型元素的数组在 C# 中是协变的。但是这会在运行时崩溃:

mammals[0] = new Tiger();

因为哺乳动物是真的是一群长颈鹿.

这意味着每次你write到一个数组,其元素是未密封的引用类型,运行时执行类型检查如果类型检查失败可能会崩溃.

这是我认为的“C# 最差功能”,但事实上它确实如此work.

您的问题是“当源数组是值类型数组而目标数组是引用类型数组时,为什么数组协方差不起作用?”

Because 这两件事在运行时有不同的形式。假设你有一个byte[]有十个元素。为数组元素保留的实际存储空间为十个字节长。假设您使用的是 64 位计算机,并且您有object[]有十个元素。存储空间扩大了八倍!

显然你无法转换通过引用转换对十个字节的存储的引用对十个八字节的存储的引用。额外的 70 个字节并不是凭空产生的;而是有的。必须有人分配它们。

而且:谁打拳击?如果您有一个包含十个对象的数组,并且每个对象都是一个字节,那么这些字节中的每一个都是boxed。但字节数组中的字节没有装箱。那么当你进行转换时,谁来进行拳击呢?

一般来说,在 C# 中,协变转换始终保留表示形式。 “对动物的引用”的表示与“对长颈鹿的引用”的表示完全相同。但“int”和“对象引用”的表示完全不同。

人们期望将一种数组类型转换为另一种数组类型不会分配并复制一个巨大的数组。但我们不能拥有参考身份介于十个字节的数组和包含十个引用的八十个字节的数组之间,因此整个事情都是非法的。

现在,你可能会说,好吧,当表征是相同的对于值类型?事实上,这在 C# 中是非法的:

int[] x = new uint[10];

因为在 C# 中,规则是只有仅涉及引用类型的协变数组转换才是合法的。但如果你强制它由运行时完成:

int[] x = (int[])(object) new uint[10];

然后运行时允许它,因为四字节 int 和四字节 uint 具有相同的表示形式。

如果您想更好地理解这一点,那么您可能应该阅读我关于 C# 中协变和逆变如何工作的整个系列文章:

  • 整个系列

  • 不安全参考元素数组协方差的细节

  • 有关值元素数组协方差的更多信息

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

无法将值类型数组转换为 params object[] 的相关文章

  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • .NET 中是否有内置函数可以对密码进行哈希处理?

    我看到这个问题加密 散列数据库中的纯文本密码 https stackoverflow com questions 287517 encrypting hashing plain text passwords in database 我知道我
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • OleDbDataAdapter 未填充所有行

    嘿 我正在使用 DataAdapter 读取 Excel 文件并用该数据填充数据表 这是我的查询和连接字符串 private string Query SELECT FROM Sheet1 private string ConnectStr
  • 重载<<的返回值

    include
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • 这些作业之间是否存在顺序点?

    以下代码中的两个赋值之间是否存在序列点 f f x 1 1 x 2 不 没有 在这种情况下 标准确实是含糊不清的 如果你想确认这一点 gcc 有这个非常酷的选项 Wsequence point在这种情况下 它会警告您该操作可能未定义
  • 使用 x509 证书签署 json 文档或字符串

    如何使用 x509 证书签署 json 文档或字符串 public static void fund string filePath C Users VIKAS Desktop Data xml Read the file XmlDocum
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • 如何在文本框中插入图像

    有没有办法在文本框中插入图像 我正在开发一个聊天应用程序 我想用图标图像更改值 等 但我找不到如何在文本框中插入图像 Thanks 如果您使用 RichTextBox 进行聊天 请查看Paste http msdn microsoft co

随机推荐