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

时间:2011-06-25 05:55:05

标签: c# java .net performance object

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

4 个答案:

答案 0 :(得分:10)

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

考虑:

int x = 10;
SomeClass y = new SomeClass();

这里,x的值确实为10 - 10的位在与变量x关联的内存中结束。

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

使用赋值时差异变得非常重要,尤其是 mutable 引用类型:

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

y1.SomeProperty = "Fred";
Console.WriteLine(y2.SomeProperty);

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

z1.SomeProperty = ...是值类型的变量时,您很少会写z1,因为大多数值类型都是不可变。 (您无法更改数据本身的值 - 您必须明确地为变量分配新值。)如果您 ,但是您不会通过以前的变量看到任何更改使用作业z1初始化,因为已在该作业中复制。

我有一个article on value types and reference types,更详细地介绍了这一切。


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

虽然拳击确实会有性能损失,但它是typically overstated in my experience。现在有了泛型,拳击并不像以前那样真正需要 - 但只要你理智地使用拳击,它就不太可能成为你应用程序中的重大性能问题。


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

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

就我个人而言,我发现控制台应用程序是学习大多数核心新概念的最简单方法 - 无论是语言功能,文件IO,集合,Web服务,线程等。显然,对于像“学习Windows窗体”这样的东西你不能做使用控制台应用程序 - 但如果没有除了Windows窗体部分之外,它真的有帮助。

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

特别是,游戏的性能要求意味着有时候写一些非惯用的C#是值得的。比如预先分配对象并在通常创建新对象的地方重用它们......甚至创建可变结构,这些结构在正常开发中几乎永远不会做。在关键的游戏循环中,装箱或创造任何的任何对象可能是一个坏主意 - 但这并不意味着这些东西在正常的参照系中是“昂贵的”。你知道什么时候这些东西是合适的,当它们不合适时...... 开始进行游戏开发时,你会得到一个不平衡的视图非常重要这些东西,IMO。您还可能尝试微观优化您真正需要的区域 - 但如果您在C#和.NET中有扎实的基础,那么您将会更好从一个角度来看待所有事情。

答案 1 :(得分:5)

只要所有出现的对象都来自System.Object,那么对于所有实际用途, 来自System.Object。在引擎盖下面,事物被优化为完美,因此int大多数时间只是一个四字节int,但它需要是一个对象时才是一个对象。这就是拳击的全部内容。

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

答案 2 :(得分:0)

拥有公共基类的一个优点意味着您可以编写类似的方法 public void DoSomething(Object object) { .... }

并且基本上传递任何东西。

不确定性能方面。

答案 3 :(得分:0)

编辑:澄清我在拳击方面的立场:当Jon让我指出时,Jon说得很好:“[拳击]和创造任何其他小物件一样昂贵”。所以,我并不是要夸大性能影响。但是,我的目的是为智能读者提供他们根据个人情况做出智能决策所需的信息。

编辑:好的,所以如果你想成为技术人员,我会收回我之前的陈述。从C#ECMA标准:“所有值类型都隐式地从类对象继承。任何类型都不可能从值类型派生,因此值类型被隐式密封(第17.1.1.2节)。” (C#ECMA标准第130页)但是......我的理解是,OP问题的主旨实际上与性能有关,以及如何在.NET中引入类型。到目前为止:值类型与参考类型的处理方式不同 - 简单类型(int,float等)以有效的方式存储和操作。当他们像对象一样对待时,您需要支付昂贵的性能成本(正如OP所怀疑的那样)。这个故事的寓意是,对我而言,希望也许是其他人,是避免拳击 - 实际上,这意味着价值类型与对象不同......尽可能地回答我的答案。


你错了。 System.Integer和System.Float不是System.Object的子类。它们被称为“价值类型”。

你可以在文档中看到这一点:http://msdn.microsoft.com/en-us/library/system.int32.aspx表明Int是一个“struct”。

本文详细讨论了该主题:http://msdn.microsoft.com/en-us/library/34yytbws%28v=vs.71%29.aspx

如果您对此感兴趣,请务必阅读最后一篇。

关于更广泛的问题,“为什么C#中的大多数类型都继承自System.Object”,你会发现没有什么独特之处。 Java有java.lang.Object,Objective-C有NSObject等。值类型和引用类型之间的区别几乎是通用的。我不确定我是否真的需要在这里找到冗长的答案,因为我认为指出差异,而关于C#中值类型的文章已经回答了你的问题。

澄清其他人关于拳击等的问题:http://msdn.microsoft.com/en-us/magazine/cc301569.aspx