为什么C#中的大多数类型都是从System.Object继承的?

App*_*ker 7 .net c# java performance object

我正在检查C#中的int和float类型,甚至他们有"ToString"等方法,这意味着它们是从System.Object继承的.但这不会导致性能下降吗?据我所知,由于性能的原因,他们没有像java中的int对象那样创建基类型.这个规则也不适用于.NET吗?如果确实如此,那么这意味着.NET比Java慢吗?但实际上并非如此,因为我在C#中创建的程序比我在Java中编写的程序要好.那么我有什么不明白的地方吗?

Jon*_*eet 10

理解值类型和引用类型之间的差异非常重要.差异的核心是该类型的表达式的值是什么.

考虑:

int x = 10;
SomeClass y = new SomeClass();
Run Code Online (Sandbox Code Playgroud)

这里,real的值x是10 - 10的位在与变量相关的存储器中结束x.

y是一个引用 - 一种获取内存中单独对象的方法.

使用赋值时,差异变得非常重要,特别是对于可变引用类型:

int x1 = 10;
int x2 = x1;
SomeClass y1 = new SomeClass();
SomeClass y2 = y1;

y1.SomeProperty = "Fred";
Console.WriteLine(y2.SomeProperty);
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,变量的值都会在赋值中复制 - 所以它x2的值是10; y2的值是对同一个对象引用.因此,当通过倒数第二个中的属性修改对象的数据时,您仍然可以看到这种差异y2.

z1.SomeProperty = ...z1值是类型的变量时,您很少会写,因为大多数值类型都是不可变的.(您不能更改数据本身的值 - 您必须明确地为变量赋值.)如果您这样做了,但是您不会通过先前使用赋值初始化的变量看到任何更改,z1因为将被复制在该作业中.

我有一篇关于值类型和引用类型文章,它更详细地介绍了所有这些.


现在,C#和.NET有一个统一的类型系统,使得即使值类型继承System.Object.这意味着您可以从Object值类型值调用所有消息.有时需要装箱(将值类型值转换为一个Object),有时它不会...我现在不会涉及所有规则.重要的是,如果值类型覆盖对象方法(例如ToString,或GetHashCode),不需要将值加框以调用该方法.

虽然拳击确实有性能损失,但在我的经验中,这通常被夸大了.这些天使用泛型,拳击并不像以前那样真正需要 - 但只要你只是理智地使用它,它就不太可能成为你应用程序中的重要性能问题.


编辑:关于游戏,表演和一次学习的东西......

我见过很多人在不了解基础知识的情况下就一个相对高级的主题提问.显然,作为一名初学者并没有什么不妥,但在我看来,在"新手友好"的环境中首先学习基础知识非常重要 - 我认为这并不算游戏.

我个人认为控制台应用程序是学习大多数核心新概念的最简单方法 - 无论是语言功能,文件IO,集合,Web服务,线程等.显然,对于像"学习Windows窗体"这样的东西,你不能用控制台应用程序 - 但除了Windows窗体部分之外的任何内容对您来说都是新的,这确实很有帮助.

所以我强烈建议你在进入游戏之前学习C#的基础知识 - 比如值类型和引用类型如何工作,参数传递如何工作,泛型,类,继承等.这可能听起来像额外的工作,但它可能会节省你的时间.当某些事情没有按照您的预期行事时,您就会知道该语言是如何工作的,因此您可以专注于API的行为方式不同等等.根据我的经验,尝试一次学习一件事会使整个过程更加顺畅.

特别是,游戏的性能要求意味着有时候写一些非惯用的C#是值得的.像预先分配对象和重复使用它们通常会创建新对象的事情......甚至创建可变结构,我在正常开发中几乎从不这样做.在关键的游戏循环中,装箱或创建任何对象可能都是一个坏主意 - 但这并不意味着这些东西在正常的参照系中是"昂贵的".这是非常重要的,你知道这事是合适的,而当他们不...如果你开始与游戏的发展,你会得到这些东西的不平衡来看,IMO.您还可能尝试微观优化您真正不需要的区域- 但如果您在C#和.NET中拥有坚实的基础,那么您将能够更好地了解所有内容.


Ric*_*key 5

只要所有对象看起来都是从中派生出来的System.Object,那么对于所有实际目的,它们都是从中衍生出来的System.Object.在引擎盖下面,事物被优化为完美,因此在大多数情况下inta只是一个四字节int,但它是一个需要成为对象的对象.这就是拳击的全部意义.

编译器和运行时都非常非常努力地确保原始类型不会因大小或功能上的大量超重负担而负担过重.同时,确保满足C#规范和对象层次结构所需的所有规则.有时编译器采用快捷方式,有时运行时会完成工作.

  • @Steve:但他们**似乎是**.那是OP的问题.从C#4.0规范4.1.1:_All值类型隐式继承自System.ValueType类,而System.ValueType又继承自类object_ (2认同)