C#100问--为什么值类型不允许定义无参构造函数?

2024-01-13 07:58

本文主要是介绍C#100问--为什么值类型不允许定义无参构造函数?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

直接回答:
为了防止开发人员对这种构造器在什么时候调用产生迷惑,导致发生影响程序性能的问题,所以干脆禁止。

详细解答:
首先CLR是允许这种行为的,只是C#编译器不允许。
当程序new一个无参的值类型时,会分配一片内存(该片内存是已经分配过的),并将这片内存的脏数据(之前存储了一些其他数据)清理掉,即zeroed,这个工作是CLR调用IL形式的initobj指令完成的。当程序new一个无参的值类型时,new操作符就被编译成initobj指令。

考虑到有些情况会使用无参构造函数,而有些情况不能使用,容易造成困惑,破坏了一致性,所以干脆禁止。比如以下这个例子:

Struct[] foo = new Struct[1000];

对于上面这个语句,CLR可以通过分配内存并zeroed化内存的方式高效完成。但如果定义了无参构造函数的话,也就意味着要执行1000次无参构造函数,极其低效。


延申问题:在struct中定义一个值类型并赋值,则会发生什么?
会编译报错:结构中不能有实例字段初始值设定项。
原因就是C#不允许为值类型定义无参构造函数,所以不会自动执行内联初始化,所以不能在值类型中内联实例字段的初始化,他们总是被初始化为0或null。

struct SomeValType
{// 不能在值类型中内联实例字段的初始化private int m_x = 5;
}

延申知识点:
值类型若要显示定义有参构造函数,则必须对所有字段显示赋值

struct SomeValType
{private int m_x;private int m_y;public SomeValType(int x, int y){m_x = x;m_y = y;}
}

或者用这种方式

struct SomeValType
{private int m_x;private int m_y;public SomeValType(int x, int y){// 会将所有字段全部赋值为0this = new SomeValType();// 用x覆盖m_x的0m_x = x;   }
}

替代方案中用到的this在值类型中,this可赋值,因为它是一个实例。
而引用类型中,this只读不可赋值。

这篇关于C#100问--为什么值类型不允许定义无参构造函数?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/600743

相关文章

在C#中分离饼图的某个区域的操作指南

《在C#中分离饼图的某个区域的操作指南》在处理Excel饼图时,我们可能需要将饼图的各个部分分离出来,以使它们更加醒目,Spire.XLS提供了Series.DataFormat.Percent属性,... 目录引言如何设置饼图各分片之间分离宽度的代码示例:从整个饼图中分离单个分片的代码示例:引言在处理

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

MyBatis中的两种参数传递类型详解(示例代码)

《MyBatis中的两种参数传递类型详解(示例代码)》文章介绍了MyBatis中传递多个参数的两种方式,使用Map和使用@Param注解或封装POJO,Map方式适用于动态、不固定的参数,但可读性和安... 目录✅ android方式一:使用Map<String, Object>✅ 方式二:使用@Param

C# 预处理指令(# 指令)的具体使用

《C#预处理指令(#指令)的具体使用》本文主要介绍了C#预处理指令(#指令)的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录1、预处理指令的本质2、条件编译指令2.1 #define 和 #undef2.2 #if, #el

C#实现将Excel工作表拆分为多个窗格

《C#实现将Excel工作表拆分为多个窗格》在日常工作中,我们经常需要处理包含大量数据的Excel文件,本文将深入探讨如何在C#中利用强大的Spire.XLSfor.NET自动化实现Excel工作表的... 目录为什么需要拆分 Excel 窗格借助 Spire.XLS for .NET 实现冻结窗格(Fro

C# Semaphore与SemaphoreSlim区别小结

《C#Semaphore与SemaphoreSlim区别小结》本文主要介绍了C#Semaphore与SemaphoreSlim区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录一、核心区别概览二、详细对比说明1.跨进程支持2.异步支持(关键区别!)3.性能差异4.API 差

C# List.Sort四种重载总结

《C#List.Sort四种重载总结》本文详细分析了C#中List.Sort()方法的四种重载形式及其实现原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录1. Sort方法的四种重载2. 具体使用- List.Sort();- IComparable

C#中Trace.Assert的使用小结

《C#中Trace.Assert的使用小结》Trace.Assert是.NET中的运行时断言检查工具,用于验证代码中的关键条件,下面就来详细的介绍一下Trace.Assert的使用,具有一定的参考价值... 目录1、 什么是 Trace.Assert?1.1 最简单的比喻1.2 基本语法2、⚡ 工作原理3