56

请帮助我们解决“几乎”一切都是对象的争议(对 Stack Overflow 问题的回答作为新手,在学习 C# 之前有什么需要注意的吗?)。我认为情况就是这样,因为 Visual Studio 中的所有内容至少都以结构的形式出现。请张贴参考,以免它变成“现代蠢货”(This American Life)。

请注意,这个问题指的是 C#,不一定是 .NET,以及它如何处理后台数据(显然都是 1 和 0)。

以下是对“一切都是对象”的评论:

  • 呃,不,不是。– 二元忧虑者
  • 我想要一个例子... – scotty2012
  • 不是所有东西都派生自基本类型 Object 吗?– 细雨
  • 大多数东西都是对象...... – Omar Kooheji
  • 值类型、整数、双精度、对象引用(不是它们本身的对象)等都不是对象。它们可以“装箱”以看起来像对象(egiToString()),但实际上它们是原始类型。将条目更改为“几乎所有事物都是对象”,我将删除反对票 – Binary Worrier
  • 我很欣赏澄清。我认为您可以在 C# 中与之交互的最低级别(例如 int)是作为结构,而不是对象?- http://msdn.microsoft.com/en-us/library/ms173109.aspx – rizzle
  • Int32 不是继承自 Object 的 ValueType 吗?如果是这样,尽管有这种行为,但 int 是一个对象。——克里斯·法默
  • 不,int 的装箱类型继承自 ValueType,ValueType 继承自 Object。它们不是传统意义上的对象,因为 a) int 不是对 int 的引用,它是 int。b)整数不是垃圾收集的。如果您声明一个 Int32,那么该 int 在堆栈上是 4 个字节,故事结束 – Binary Worrier

对象的定义:“对象”作为类 System.Object 的继承者,“对象”作为类型的实例,“对象”作为引用类型。

4

17 回答 17

81

这里的问题是这实际上是两个问题——一个是关于继承的问题,在这种情况下答案是“几乎所有”,另一个是关于引用类型与值类型/内存/装箱的问题,在这种情况下答案是“否” ”。

遗产:

在 C# 中,以下是正确的:

  • 所有值类型,包括枚举和可为空的类型,都派生自System.Object.
  • 所有类、数组和委托类型都派生自System.Object.
  • 接口类型不是从System.Object. 它们都可以转换为System.Object,但接口只派生自其他接口类型,而System.Object不是接口类型。
  • 没有指针类型派生自System.Object,也不能直接转换为System.Object
  • “开放”类型参数类型也不是从System.Object. 类型参数类型不是从任何东西派生的;类型参数被限制为从有效的基类派生,但它们本身不是从任何东西“派生”的。

System.Object 的 MSDN 条目

支持 .NET Framework 类层次结构中的所有类,并为派生类提供低级服务。这是 .NET Framework 中所有类的终极基类;它是类型层次结构的根。

语言通常不需要类来声明从 Object 的继承,因为继承是隐式的。

因为 .NET Framework 中的所有类都派生自 Object,所以 Object 类中定义的每个方法在系统中的所有对象中都可用。派生类可以并且确实会覆盖其中一些方法。

因此,并非 C# 中的每种类型都派生自System.Object. 即使对于那些类型,您仍然需要注意引用类型值类型之间的区别,因为它们的处理方式非常不同。

拳击:

虽然值类型确实继承System.Object,但它们在内存中的处理方式与引用类型不同,并且它们如何通过代码中的方法传递的语义也不同。实际上,值类型不会被视为对象(引用类型),除非您通过将其装箱为引用类型来明确指示您的应用程序这样做。在此处查看有关 C# 中的装箱的更多信息

于 2009-01-12T17:29:53.773 回答
31

聚会有点晚了,但我在 SO 的搜索结果中发现了这一点,并认为下面的链接会对后代有所帮助:

Eric Lippert非常彻底地讨论了这一点,并给出了一个更好(合格)的声明:

纠正这个神话的方法是简单地将“派生自”替换为“可转换为”,并忽略指针类型:C# 中的每个非指针类型都可以转换为对象。

如果您讨厌从编写编程语言的人那里阅读详细说明的解释,那么它的要点是(除了指针),接口或泛型参数类型声明(“T”)之类的东西不是对象,但保证是在运行时可被视为对象,因为它们有一个明确的实例,这将是一个对象。其他类型(类型、枚举、委托、类等)都是对象。包括值类型,正如其他答案所讨论的那样,可以将其装箱为对象。

于 2009-08-13T11:51:57.413 回答
15

这里有些人对面向对象编程中的“对象”有一个奇怪的概念。为了使某物成为对象,它不必引用类型,或者更一般地说,遵循任何正式的实现。

这意味着您可以在面向对象的世界中作为一等公民对其进行操作。由于您可以在 C# 中对值执行此操作(多亏了自动装箱),所以一切都确实是一个对象。在某种程度上,这甚至适用于函数(但可以说不适用于类)。

这在实践中是否相关是另一个问题,但这是我再次注意到的 OOP 的普遍问题。没有人对 OOP 的定义很清楚(是的,大多数人都同意它与多态性、继承和封装有关,有些人为了更好地衡量了“抽象”)。

从使用的角度来看,C# 中的每个值都像对象一样处理。也就是说,我喜欢当前接受的答案。它提供了两个技术上重要的方面。

请注意,在其他上下文中,例如 C++,强调其他方面,因为 C++ 不一定是面向对象的,而且更侧重于低级方面。因此,对象、POD 和内置原语之间的区别有时是有意义的(但有时又不是)。

于 2009-01-12T18:05:47.367 回答
8

您将对象与值或引用混淆了。基本上,一切都是对象。Int 是一个对象,但它也是一个值类型。类实例是一个对象,但它也是一个引用类型。

方法不是对象,属性也不是。只是对对象进行操作。是的,几乎所有东西都继承自对象类。

于 2009-01-12T17:32:34.173 回答
6

在 C#(以及一般的 OOP 中)中,我们有类型(类 - 引用、结构 - 值等)。这些是定义。而“对象”是给定类型的具体实例。

所以,如果我们从字面上理解这个问题,是的,当实例化时,一切都是对象。

混乱很可能始于对所有事物的基类名称的错误选择。在.NET中,这是 Object 类。

于 2009-01-12T17:41:24.093 回答
5

它们都被视为对象,但它们并非都是对象。混淆来自自动装箱。

有关更多信息,请参见:http ://en.wikipedia.org/wiki/Object_type

抽象显然使人们感到困惑。

于 2009-01-12T17:40:45.407 回答
4

我认为值类型不是对象。它们通过 CLR 以不同的方式存储在内存中 - 值类型存储在堆栈中,而对象存储在堆中。您可以将值类型强制转换为引用类型以使它们像对象一样工作,但 CLR 从堆栈中取出值,将其包装在对象中,然后将其存储在堆中。这就是当你“装箱”一个变量时发生的事情。

于 2009-01-12T17:34:42.610 回答
4

来自:值类型(C# 参考)- MSDN 3.5

所有值类型都是从 System.ValueType 隐式派生的。

来自:值类型类 - MSDN 3.5

ValueType 使用更合适的值类型实现覆盖来自 Object 的虚拟方法。

来自:枚举类 - MSDN 3.5

这个类继承自 ValueType

继承层次结构如下:

  • 系统对象
    • System.ValueType
      • 系统枚举

结论:一切都是对象

于 2009-01-12T18:09:58.437 回答
3

根据我读过的所有书籍,C# 中的一切都是对象。

有些是参考,有些是值类型。值类型对象继承自ValueType类。他们有不同的行为,但本质上是……对象。

这就是为什么您可以将 Int32 以及您可以在 .NET 中创建的所有内容存储在对象变量中的原因。

有关更多详细信息...请查看以下内容:http: //msdn.microsoft.com/en-us/library/s1ax56ch (VS.71).aspx

所有值类型都是从 Object 类隐式派生的。

于 2009-01-12T17:31:02.290 回答
3

虽然每个人似乎都在关注值类型与引用类型的争论,但我们忘记了 C# 中的一种类型,它既不是引用也不是值,它不是从对象派生的,也不能强制转换为对象:指针。

与值和引用类型不同,指针不能转换为对象。

根据关于 C# 指针类型的 MSDN 文档

指针类型不继承自对象,并且指针类型和对象之间不存在转换。此外,装箱和拆箱不支持指针。但是,您可以在不同的指针类型之间以及指针类型和整数类型之间进行转换。

于 2009-01-13T17:05:32.683 回答
2

简短的回答:

答案取决于“对象”的定义。不同的语言对“对象”的含义有不同的定义,但 C# 的权威定义是官方的C# 语言规范

C# 语言的类型主要分为两大类:引用类型值类型。(...) 值类型与引用类型的不同之处在于,值类型的变量直接包含它们的数据,而引用类型的变量存储对其数据的引用,后者被称为对象

因此,根据 C#,对象是引用类型的实例。因此,值类型值不是对象。因此,在 C# 中一切都是对象是不正确的。

然而:

C# 的类型系统是统一的,因此任何类型的值都可以被视为对象。(...) 值类型的值通过执行装箱和拆箱操作(第 9.3.12 节)被视为对象。

因此,可以通过装箱将值类型视为对象(有效地变成引用类型)。但是一个未装箱的值类型本身并不是一个对象。

CLR 规范[PDF] 使用与 C# 非常相似的定义:

object:引用类型的实例。一个对象比价值更重要。一个对象是自键入的;它的类型显式地存储在它的表示中。它具有将其与所有其他对象区分开来的标识,并且它具有存储其他实体(可以是对象或值)的插槽。虽然可以更改其插槽的内容,但对象的身份永远不会改变。

因此,在 CLR 术语中,值类型值也不是对象。

于 2009-01-13T16:52:19.700 回答
1

解决语义,当我们已经有一个非常好的、明确的术语时,为什么要重载“对象”这个词,使它意味着“引用类型”->“引用类型”,以及何时,通过重载“对象”这个词这样我们就造成了这个线程演示的混乱......即,所有类型(包括值类型)都继承了“System.Object”类型中定义的实现这一事实之间的不匹配。显然,这充其量是不必要的,最坏的情况是极其混乱。即使 MS 文档有时在这个问题上令人困惑这一事实也不能成为传播混乱的借口。

更简单、更清晰的是,只定义和使用术语“对象”来表示任何类型、值或引用的实例,并使用短语“引用类型”来描述使用指针变量并存储其状态的类型堆...

于 2009-04-24T13:36:24.733 回答
0

数字 2 不是一个对象。

于 2009-01-12T17:31:31.260 回答
0

这是对两个世界的讨论:语言和记忆。

对我来说,语言就像一个抽象层,而术语对象属于这个抽象层。我认为在内存组织方面谈论对象没有意义,如果在谈论内存时确实使用“对象”术语,那么实际上是从不同的抽象层借用了这个术语。因此,您不应该忘记它的来源。

如果我们谈论的是 C#,我不明白为什么有人会使用内存组织作为论据。当然,如果我要向某人回答这个问题,我会说“是的,在 C# 中,一切都是对象,但你也应该知道,在引擎盖下,它可能会根据......而不同地工作。”

这可能会引发一个有趣的论点,但也可能会引起一些人的注意:在类似的讨论中,人们可能会说实际上没有面向对象的编程,只有过程编程。你的 CPU 理解对象吗?更好的是,实际上没有软件,只有不同的硬件状态:)

我的观点是,某些术语不会转化为其他抽象层,您应该将讨论集中在它所属的位置(在这种情况下是一种语言,而不是记忆)。

甚至这个问题的作者也说:“请注意,这个问题涉及 C# 不一定是 .NET 以及它如何处理后台数据(显然它都是 1 和 0。)”

于 2009-04-24T13:06:43.667 回答
-1

值类型不是对象,它们遵循不同的复制语义、不同的传递语义,并且必须包装在一个类(对象)中才能被这样对待。

编辑:我认为这个论点有些模糊,因为你必须限定你所说的“对象”的意思。对象只是继承自 Object 的东西,还是遵循 Object 的使用语义的东西?还是我们在谈论对象的最一般定义,它是指可以包含数据和对该数据进行操作的任何东西?

于 2009-01-12T17:31:16.453 回答
-1

考虑到问题是指 OOP 意义上的 Object,答案是:

技术角度来看,答案是:

教条的角度来看,答案是:是的

解释:

从技术上讲,值类型(原语或结构)不是对象,除非是“装箱”形式,但是因为 .Net 通过装箱/拆箱(创建一个保存值的类实例和派生自 Object),这意味着值类型可以被视为对象和简单值。

所以值类型本质上是双重的,它们表现为对象。.Net 中的值在需要时是对象,而在其他情况下它们不是对象。

考虑到技术方面的正确答案是“.Net 中的一切都好像它是一个对象”。

教条的答案是“一切都是对象”。

于 2009-01-13T12:46:47.650 回答
-3

有这么多不同答案的原因之一是这个问题非常不精确。“一切”是什么意思?它真的意味着每个 C# 语言元素吗?那么答案显然是“否”:运算符不是对象,“using”关键字不是对象,注释不是对象,等等。

但如果这不是本意,那又是什么意思呢?也许“除了那些显然不是类的东西之外的所有东西”?这显然没有帮助,因为不同的人对什么是“显而易见的”有不同的看法。尽管如此,大多数答案似乎都遵循这种自以为是的解释。

另一个混淆的来源是“对象”一词。什么是对象?这个术语没有唯一的通用定义,不同的人似乎以不同的方式使用它。C# 语言中唯一的正式定义是 System.Object 类型的定义,以及哪些其他类型派生自它,哪些不是。该文档很容易获得,并且不能说更多。

于 2020-08-08T20:55:35.760 回答