关于int a = 1 ; a.ToString();的一个小疑惑

长颈鹿CTZ 2017-11-22 02:34:29
加精
int a = 100;
string str = a.ToString();

a是值类型的 ,但a这个变量能调用方法,说明他是一个对象,而对象是引用类型的 ,前后矛盾

我是从Java转过来的,第一次见到这样的写法是崩溃的,毕竟Java里面有int装箱后的引用类型Integer,而C#没有
...全文
7208 27 打赏 收藏 举报
写回复
27 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
public struct Int32 : IComparable, IComparable<int>, IConvertible, IEquatable<int>, IFormattable int 不过是int32结构 的别名
  • 打赏
  • 举报
回复
CDboyOne 2018-12-10
前面几位是回答可能会引起新手的误解,所以我来解释一下:值类型的确间接地继承 Object 类型,但不要因此把值类型看作引用类型。

我们先来考虑一下值类型和引用类型的本质。

首先,为什么前面几位都说 int 类型的变量也是一个对象呢?对于 C# 内置的值类型,全部隐式派生于 System.ValueType 类型,而后者正是继承了 Object 类型。这也是 C# “纯粹的面向对象” 的理念的体现。

但是!C# 对值类型和引用类型的处理是不一样的。怎么不一样呢?我们都知道,将一个引用类型变量赋给另一个时,两个变量指向同一个对象;但如果你将一个值类型变量赋给另一个,那么分别与两个变量有关的内存区域是不一样的!

然后,我们再具体考虑楼主的问题。

为什么一个 int 类型的变量会具有 ToString 方法?这是因为在 C# 语言环境中,所有的值类型都表现为一个结构体!int 类型是这样,char, float 等等也是这样;同样,你自己定义值类型的时候,也是在定义一个结构体。

那么结构体和类有什么区别?微软文档里面有一些解释,《果壳中的 C#》一书中也有详细介绍,我会在末尾给出微软文档的链接。除去一些语法细节,结构体除了不支持继承,以及默认的赋值行为不同于类,其他方面与类是相同的。也就是说,结构体同样可以具有方法和属性。

至此,楼主的问题就得到了解答:之所以能调用那个方法,是 System.Int32 这个结构体本身就有这个方法,跟引用类型并没有关系。

微软对于值类型的解释:https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/value-types

如果对值类型没理解到位,可以写几行代码试试结构体之间的赋值,然后再做下面的事情:

定义一个结构体 Interval,具有 Low 和 High 两个成员变量(其实无所谓啦);然后定义一个类 Tree,具有一个 Interval 类型的属性 Value,该属性拥有 get 和 set 访问器。在 Main 函数中实例化 Tree 的一个对象 tree,以及一个 Interval 类型的变量 i,然后写这样的一条语句:tree.Value = i。你会发现这条语句会报错。为什么呢?自己想啦。
  • 打赏
  • 举报
回复
tutubear821 2017-12-01
十分感谢楼主!
  • 打赏
  • 举报
回复
xiaoxiangqing 2017-12-01
平时没注意这些,刚才看了源码,确实是用的它自己的方法
  • 打赏
  • 举报
回复
zwy9764316497 2017-11-24
太高端 不懂.. 但是略微一看 我只能说Java垃圾 哈哈.. Java之王还在吗? 是被人打死了吗?
  • 打赏
  • 举报
回复
长颈鹿CTZ 2017-11-24
引用 1 楼 caozhy 的回复:
这叫装箱拆箱(inboxing and outboxing),和java不同,java的int有外覆类Integer 而C#,是自动装箱拆箱的。也就是当你调用a.ToString()的时候,CLR会自动将a放入一个引用对象(类似Java的Integer),这就叫装箱。 而当你从装箱的对象中取出整数,它又会拆箱。比如 ArrayList1.Add(a); //a会被放入“箱”,再存入列表。 int x = ArrayList1[0]; //此时又会拆箱,并且结果送到x上。 装箱拆箱的目的是在不增加程序本身复杂度的情况下,对系统性能的优化。 Java的外覆类,使得程序员要为值类型编写额外的代码。
经过广泛的查阅资料,有这样的说法 int a = 100; a.ToString(); 并没有进行装箱操作,只不过是调用结构体Int32的方法,与4楼的观点一致 您确定a.ToString()这里进行了装箱操作吗?
  • 打赏
  • 举报
回复
面向对象的写法是对象后边打“点儿”然后写方法名,这并不意味着每一个对象都复制一遍自己私有的“函数列表”到对象结构中。那只是一种想法,就算是 java 或者 ms c++是这么实现的,不代表着 .net 机制/c# 编译器就是这么实现的。 实际上不同的面向对象语言的编译器、甚至同一种的不同编译器版本都可能在底层有不同的实现形式。可以说 java、c++、c# 必定不同!所以死抠底层机制不行,但是从未又动手实现底层机制而只会简单使用也不行。
  • 打赏
  • 举报
回复
引用 17 楼 snlixing 的回复:
msdn上解释是将此实例的数值转换为其等效的字符串表示形式。
lz 其实是问为什么一个 int 后边可以打“点儿”然后写方法名,问这种语法的机制。
  • 打赏
  • 举报
回复
snlixing 2017-11-23
msdn上解释是将此实例的数值转换为其等效的字符串表示形式。
  • 打赏
  • 举报
回复
更明白地说,对象并不需要什么函数指针列表,对象类有函数指针列表就行了。所以面向对象设计,低级的部分还是面向过程的,运行时还是按照低级的东西来执行,我们在设计时追求的是应用而不是低级的部分。
  • 打赏
  • 举报
回复
越是高层的业务领域设计,也就越容易充满着新奇的面向对象概念。但是不要不关心底层,不要把基本的机制理解错误。对象并不是非要有什么“函数指针列表”,你是从另外一种方式去理解底层机制的了。
  • 打赏
  • 举报
回复
面向对象编程语言,底层当然当然还是基于面向过程的方法来搭建。并不是说动不动就把它们对立起来,只是说有层次高低之分。所以设计、理解程序有的人从高层着手,有的人永远也理解不了“面向应用领域的设计”而只能记住底层的一些东西。 int 本身十分非常底层的东西,所以它也就容易跟高层的“业务对象”产生歧义。无论如何,调用一个对象的 ToString 方法,也就是调用这个“类型”的 ToString 方法,并且把对象(int 对象)作为它的 this 参数而使用。为什么说“只有引用对象才能调用方法”呢? 这里你认为的“调用方法”的机制本身就是错的了。
  • 打赏
  • 举报
回复
闭包客 2017-11-23
java 没有 struct,int 这种类型是特殊处理的。
  • 打赏
  • 举报
回复
by_封爱 版主 2017-11-23
太高端 不懂.. 但是略微一看 我只能说Java垃圾 哈哈.. Java之王还在吗? 是被人打死了吗?
  • 打赏
  • 举报
回复
疯羽翼 2017-11-23
系统重写了ToString();的方法, 你也可以对int 进行扩展的方法 比如: public static class A{ public static string ToCH(this int a){ return a.ToString(); } } 那么所有类型为int 都可以调用 ToCH的方法
  • 打赏
  • 举报
回复
闭包客 2017-11-22
值类型同样有自己的函数,这和面向对象编程并不矛盾。
  • 打赏
  • 举报
回复
threenewbee 2017-11-22
我不知道你开什么车。这就好比你开的车,现在的车从物理设计上说,根本没有“油门”这个概念了。 对于电喷的内燃机引擎,“油门”其实是节气门,它控制的是节气门的开度,而不是喷油量,喷油量是车内的ECU控制的。 对于电动车,“油门”其实控制的是电机的输出功率,也和喷油量毫无关系。 既然油门不是油门,为什么我们还把它叫做油门,因为虽然底层的实现完全不同,但是对于驾驶员来说,这是透明的,不因为你开了新的汽车要重新学习一遍。 类似的,int在程序员的角度来说,它也是对象,但是在CLR层面,它不是。
  • 打赏
  • 举报
回复
threenewbee 2017-11-22
引用 5 楼 pandaball 的回复:
[quote=引用 1 楼 caozhy 的回复:] 这叫装箱拆箱(inboxing and outboxing),和java不同,java的int有外覆类Integer 而C#,是自动装箱拆箱的。也就是当你调用a.ToString()的时候,CLR会自动将a放入一个引用对象(类似Java的Integer),这就叫装箱。 而当你从装箱的对象中取出整数,它又会拆箱。比如 ArrayList1.Add(a); //a会被放入“箱”,再存入列表。 int x = ArrayList1[0]; //此时又会拆箱,并且结果送到x上。 装箱拆箱的目的是在不增加程序本身复杂度的情况下,对系统性能的优化。 Java的外覆类,使得程序员要为值类型编写额外的代码。
string str = 100.ToString(); 这种写法的解释是说 CLR将100默认装箱为Object 了吗?[/quote] 注意,装箱的那个对象,当然是Object的派生类,但是不是Object,你可以理解为一个相当于Java Integer那样的类,只是它在C#里不存在,在CLR里匿名。 再说一遍,装箱拆箱的目的是在不增加程序本身复杂度的情况下,对系统性能的优化。 也就是从程序员的角度看,int,或者说值类型也是对象,它也从Object派生。但是这只是一个错觉。在CLR层面,它们不是对象。
  • 打赏
  • 举报
回复
https://referencesource.microsoft.com/#mscorlib/system/int32.cs 你会发现 int不过是一个对象。
  • 打赏
  • 举报
回复
ourhouzi 2017-11-22
万物皆对象 值类型也是对象
  • 打赏
  • 举报
回复
加载更多回复
相关推荐
发帖
C#
加入

10.7w+

社区成员

.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
申请成为版主
帖子事件
创建了帖子
2017-11-22 02:34
社区公告

让您成为最强悍的C#开发者