C#l编译器是否会为值类型生成默认的构造函数!
C#编译器是否会为值类型生成默认的构造函数呢?
答案是否定的,C#编译器并不会为值生成默认的构造函数的,这样设计一方面是基于性能方面的考虑,另外一个原因是值类型可以被隐式的创建!这一点可以通过ILDasm工具开验证,值类型确实没有生成默认的构造函数,看下面的代码:
class Program
{
static void Main(string[] args)
{
A a =new A();
}
}
struct A
{
}
有人可能比较奇怪:A a=new A();这行是需要调用结构体的默认构造函数的,如果没有生成默认的构造函数,这里应该同不过编译的,事实正如大家预料的,这行代码可以通过编译的!
这里似乎有自相矛盾的地方啊!先别急,我们先看看Main方法的IL代码:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// 代码大小 10 (0xa)
.maxstack 1
.locals init ([0] valuetype ConsoleApplication1.A a)
IL_0000: nop
IL_0001: ldloca.s a
IL_0003: initobj ConsoleApplication1.A
IL_0009: ret
} // end of method Program::Main
我们看红色的代码行,第一行是把局部变量a入栈,第二行是初始化a,注意使用的是initobj指令,这里调用的是隐式的默认的构造函数,因为每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值!
如果换成引用类型应该使用newobj指令,这时调用C#编译器生成的默认的构造函数了!
实际上这也就是为什么在值类型中的成员声明的同时不能直接初始化的原因,因为C#编译器根本没有为值类型生成默认的构造函数,让他何处初始化呢!
希望这篇文章能够对大家有一点帮助啊!
感谢大家的参与啊!
我在这里统一回复一下大家:
一楼说的对,在C#中,结构体是不允许定义无参的构造函数的,只能定义有参数的构造函数的,这么设计重要是为了避免引起程序员的误解!
比如这样:
Class MyClass
{
public A a;//可能有的人会误认为构造MyClass实例的时候会自动调用A的默认的构造函数,一般有C++的经验的会有这样的想法,这里C#和C++不一样
}
为了避免这种混淆,C#中并不允许在结构体中提供默认的无参构造函数!
关于结构体的用途,可能大家有一定误解!实际上在C#中结构体是很有用的,并不是仅仅为了兼容过去的遗留组件而存在。
下面我详细说说:
大家都知道结构体是值类型的,所以他的实例是存放在栈中的,而且栈的访问速度是比托管堆要快的,但是空间没有堆大!
所以可以把一些比较小的类型定义为结构来提高访问的速度,例如:
struct Point
{
int x;
int y;
}
大家可能想既然访问速度比较快,为什么不全部类型都定义为值类型的呢?道理比较简单,栈的空间并不是很大,不能存放很多的东西,另外在栈中即使是值一样的实例,往往也需要存放两份副本的,比如:
Point p1=new Point();
Point p2=p1;
在栈中就有两份p1的拷贝!
这样本身也比较占空间!
所以只有一些本身比较小的类型适合定义成结构体,大的类型最好还是定义为引用类型,放到空间相对比较大的托管堆中比较好!
再次感谢大家参与讨论啊!谢谢大家!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述