为什么我不能在 .NET 中为结构定义默认构造函数?

2024-03-25

在 .NET 中,值类型 (C#struct) 不能有没有参数的构造函数。根据这个帖子 https://stackoverflow.com/questions/203695/structure-vs-class-in-c#204009这是 CLI 规范强制要求的。发生的情况是,对于每个值类型,都会创建一个默认构造函数(由编译器?),它将所有成员初始化为零(或null).

为什么不允许定义这样的默认构造函数?

有理数的一个简单用途是:

public struct Rational {
    private long numerator;
    private long denominator;

    public Rational(long num, long denom)
    { /* Todo: Find GCD etc. */ }

    public Rational(long num)
    {
        numerator = num;
        denominator = 1;
    }

    public Rational() // This is not allowed
    {
        numerator = 0;
        denominator = 1;
    }
}

使用当前版本的 C#,默认的 Rational 是0/0这不太酷。

PS:默认参数是否有助于解决 C# 4.0 的问题,或者是否会调用 CLR 定义的默认构造函数?


乔恩·斯基特 https://stackoverflow.com/questions/333829/why-cant-i-define-a-default-constructor-for-a-struct-in-net#333840回答:

举个例子,当有人这样做时,你希望发生什么:

 Rational[] fractions = new Rational[1000];

它应该运行你的构造函数 1000 次吗?

当然应该,这就是我首先编写默认构造函数的原因。 CLR 应该使用默认归零当没有定义显式默认构造函数时的构造函数;这样您只需为您使用的内容付费。那么如果我想要一个1000个非默认的容器Rationals(并且想要优化 1000 个结构)我将使用List<Rational>而不是一个数组。

在我看来,这个原因还不足以阻止默认构造函数的定义。


Note:下面的答案是在 C# 6 之前很长时间写的,C# 6 计划引入在结构中声明无参数构造函数的能力 - 但它们仍然不会在所有情况下被调用(例如,用于数组创建)(在结束这个功能未添加到 C# 6 https://stackoverflow.com/questions/31063109/parameterless-constructors-in-structs-for-c-sharp-6)...但是然后它was 在 C# 10 中添加 https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/parameterless-struct-constructors- 但存在限制,因此您不能期望构造函数在每种情况下都运行。


编辑:由于 Grauenwolf 对 CLR 的深入了解,我编辑了下面的答案。

CLR 允许值类型具有无参数构造函数,但 C# 不允许。我相信这是因为它会引入一种期望,即构造函数在不调用时会被调用。例如,考虑一下:

MyStruct[] foo = new MyStruct[1000];

CLR 只需分配适当的内存并将其全部清零即可非常有效地完成此操作。如果必须运行 MyStruct 构造函数 1000 次,效率就会低很多。 (事实上​​,事实并非如此——如果你do有一个无参数构造函数,当您创建数组或有未初始化的实例变量时,它不会运行。)

C# 中的基本规则是“任何类型的默认值都不能依赖于任何初始化”。现在他们could允许定义无参数构造函数,但并不要求在所有情况下都执行该构造函数 - 但这会导致更多混乱。 (或者至少,所以我相信这个论点是成立的。)

编辑:以您的示例为例,当有人这样做时您希望发生什么:

Rational[] fractions = new Rational[1000];

它应该运行你的构造函数 1000 次吗?

  • 如果不是,我们最终会得到 1000 个无效理性
  • 如果确实如此,那么如果我们要用实际值填充数组,我们可能会浪费大量工作。

编辑:(回答更多问题)无参数构造函数不是由编译器创建的。就 CLR 而言,值类型不必具有构造函数 - 尽管事实证明确实如此can如果你用IL写的话。当你写“new Guid()" 在 C# 中,它发出的 IL 与调用普通构造函数时得到的 IL 不同。请参阅这个问题 https://stackoverflow.com/questions/203695/structure-vs-class-in-c关于这方面的更多信息。

I suspect框架中没有任何具有无参数构造函数的值类型。毫无疑问,如果我问得足够好,NDepend 可以告诉我... C# 禁止它的事实对我来说是一个足够大的暗示,让我认为这可能是一个坏主意。

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

为什么我不能在 .NET 中为结构定义默认构造函数? 的相关文章

  • Dapper 在执行时挂起

    我有一个 IDb连接 sql UPDATE 表名 SET json json lastupdate SYSDATE WHERE id id var param new DynamicParameters param Add json jso
  • ASP.NET - 在 RenderContent 调用中将事件处理程序添加到 Repeater 内的 LinkBut​​ton

    我有一个加载自定义用户控件的 Sharepoint WebPart 用户控件包含一个 Repeater 而 Repeater 又包含多个 LinkBut ton 在 Web 部件的 RenderContent 调用中 我有一些用于添加事件处
  • 如何在C中同时运行两个子进程?

    所以我开始学习并发编程 但由于某种原因我什至无法掌握基础知识 我有一个名为 fork c 的文件 其中包含一个 main 方法 在此方法中 我将 main 分叉两次 分别进入子进程 1 和 2 在孩子 1 中 我打印了字符 A 50 次 在
  • 组合框下拉位置

    我有一个最大化的表单 其中包含 500px 的组合框控件 停靠在右上角 Width 尝试打开组合框后 列表的一半超出了屏幕 如何强制列表显示在表单中 棘手的问题 我找不到解决这个问题的好办法 只是一个解决方法 添加一个新类并粘贴如下所示的代
  • opencv中如何去除二值图像噪声?

    将图像转换为二值图像 黑白 后如果有任何噪音怎么办 我消除了那些不需要的噪音 您可以看到下图的黑色区域内有一些白噪声 我该如何去除噪声 使用opencv http img857 imageshack us img857 999 blackn
  • 如何减少 MinGW g++ 编译器生成的可执行文件的大小?

    我有一个简单的 Hello world C 程序 在 Win XP 下由 MinGW g 编译器编译为 500kB 可执行文件 有人说这是由于iostream的库和静态链接libstdc dll Using s链接器选项有点帮助 减少了 5
  • .NET 5 EF Core SaveChangesAsync 因错误而挂起

    尽管这个问题有很多结果 但没有一个真正给我明确的答案 每次我尝试通过 AddAsync 和 SaveChangesAsync 方法插入错误数据 例如重复的主键 时 我都会看到以下日志 执行 DbCommand 失败 15 毫秒 我还在 SQ
  • 如何将STL容器数据转储到gdb中?

    我无法在 gdb 中转储 STL 无序映射容器值 变量类型是 std unordered map var 我的 gdb 版本 7 7 1 GDB配置 configure host x86 64 linux gnu target x86 64
  • 如何让XmlReader读取C#中的属性?

    我有一个 XML Stream 其中包含以下 XML 内容
  • 如何使用默认电子邮件客户端发送电子邮件?

    我想使用系统的默认电子邮件客户端 雷鸟 outlook 等 从 net windows 窗体应用程序发送电子邮件 我想预设主题和正文 我认为有一种方法可以通过向 Windows 资源管理器发送类似的内容来做到这一点 mailto 电子邮件受
  • 如何构建一棵与或树?

    我需要一个支持 与 和 或 的树结构 例如 给定一个正则表达式 如ab c d e 我想把它变成一棵树 所以 一开始我们有两个 或 分支 它可以向下ab or c d e 如果你低头ab分支 你得到两个节点 a and b or a其次是b
  • 使用数据绑定,如何将包含表情符号的文本绑定到标签并使其正确显示?

    我正在编写一个应用程序来连接 WordPress BuddyPress API 该应用程序将允许用户通过 API 相互发送消息 当这些消息包含表情符号时 我很难正确显示它们 以下是 API 返回的消息文本的简短示例 Hi x1f642 ho
  • .NET WebClient:DownloadString 在哪里?

    我可能在这里遗漏了一些东西 但是当我使用 WebClient 并查找 DownloadString 方法 如书籍示例中所示 时 我只看到 DownloadStringAsync 我缺少什么导入 您使用的是 Silverlight 吗 Sil
  • valgrind 在 Raspberry Pi 上返回未处理的指令

    我最近一直在尝试在运行 Debian GNU Linux7 0 喘息 的树莓派 型号 b 上使用 valgrind 来调试分段错误 每次我在编译的 C 程序上运行 valgrind 时 都会得到类似以下内容的信息 disInstr arm
  • 如何将System.Windows dll添加到Visual Studio 2010 Express?

    我正在开发一个小型应用程序C and VS2010 as IDE with NET框架4 我想用CaptureSource类以便从笔记本电脑的网络摄像头捕获视频 为此我需要添加一个命名空间System Windows DependencyO
  • Xcode 7 调试器不会中断内联标头函数

    过去五年我一直在各种 C 项目中使用 Xcode 没有出现这个问题 今天 我打开了一个较旧的项目 大约 2 年前 并尝试通过在该函数中放置一个活动断点来调试头文件中的内联函数 由于某种原因 调试器不会中断此代码 但是 如果我在调用该函数的
  • 使用多态对象数组进行 JSON 反序列化

    我在涉及多态对象数组的 JSON 反序列化方面遇到问题 我已经尝试过记录的序列化解决方案here https stackoverflow com questions 5186973 json serialization of array w
  • 当我的进程被终止时到底会发生什么?

    我有一个包含本机代码和托管代码的混合进程 在 Windows Server 2003 上运行 当我从进程资源管理器中终止进程时 它会进入 100 cpu 的状态 并在消失之前保持这种状态一段时间 有时甚至 10 分钟 在此期间我无法 杀死
  • 具有四个 && 的 LINQ Where 子句

    我正在尝试在Where 子句中创建一个带有4 个参数的LINQ 查询 这是一个 Windows 8 应用程序项目 我正在使用 SQLite 数据库 SQLite 实现 https github com praeclarum sqlite n
  • 使用 CodeDOM 将程序集添加到 BuildManager 会导致间歇性错误

    我正在使用 CodeDOM 在运行时创建内存中程序集 如下所示 public Assembly Compile CodeCompileUnit targetUnit string path Path GetDirectoryName new

随机推荐