我知道C#同时具有值和引用类型,但是你怎么能这样做:
int age = 100;
string blah = age.ToString();
如果age是值类型,它是如何使用ToString方法的?它是否仅在内部需要时才转换为对象?
答案 0 :(得分:11)
如果年龄是值类型,它是如何实现的 有一个ToString方法吗?
允许值类型具有方法。他们为什么不呢? “在类型上”的方法只是恰好与特定类型相关联的一大块代码;为什么你认为这种类型被归类为“参考类型”还是“价值类型”很重要?
这不是一个修辞问题。我有兴趣了解人们对代码的直觉,特别是当这些直觉不正确时。通过直观地理解人们弄错了什么,我们可以尝试提出更直观的更好的抽象。
是否仅在内部需要时才转换为对象?
“转换为对象”究竟是什么意思?你的意思是“盒装”?
在许多情况下,必须将值类型装箱。其中一些很简单 - 就像将值类型转换为对象或接口时一样。其中一些是模糊的。 (在通用方法中有一些奇怪的情况,我们必须以你可能没想到的方式装箱和拆箱。)
在这种特殊情况下,没有拳击。调用直接在值类型上实现的方法只调用那段代码。没有必要将这个东西视为“对象”;我们调用的代码块知道事物的类型。
答案 1 :(得分:6)
System.Int32
继承System.ValueType
,继承System.Object
。
所有类,结构,枚举,数组,可空和委托类型最终都是从对象派生的。所有接口类型和类型参数类型都可以隐式转换为对象。并且所有指针类型既不来自也不可转换为对象
答案 2 :(得分:6)
你想查找装箱/拆箱。
答案 3 :(得分:3)
所有Framework对象都继承自System.Object(尽管可以在MSIL中声明一个不同的类型)。
object.ToString()
方法是一种虚拟方法。
尝试从System.Object
调用方法的值类型的特殊规则是:
如果值类型覆盖了方法(因为int和所有数值类型都使用ToString()
),那么值类型不会被装箱(“转换”或“包装”到对象),但实现方法是直接打电话。
如果值类型未提供此类方法的实现(例如,自定义struct
),则会将值类型装箱,并调用基本实现的mathod。
关于装箱/拆箱的详细信息,msdn中有很多信息。
答案 4 :(得分:3)
所有类型(引用和值)都继承自Object。 (虽然像其他人一样已经说过可以定义一个没有但不在C#中的,你必须在MSIL中这样做)
这意味着任何值类型仍将继承基础对象的方法。为了使值类型在基础对象类型上调用方法,必须首先对其进行装箱,以便将其视为引用类型(装箱是获取值类型并将其推入引用类型形状框的过程,以便它表现得像参考类型)。但是在这个特定的情况下,Int32实现了它自己的ToString版本(就像大多数常见的数值类型一样),它只是值类型本身的常规方法,所以它不必被装箱来调用它。
值类型,可以像引用类型一样具有方法和属性。限制是结构(C#的值类型)不支持继承(除了Object)或终结器。
关于价值与参考类型here之间的差异,有一篇很好的文章。
答案 5 :(得分:1)
比较“值类型”与“参考类型”没有说明类型是否是对象。所有它告诉你的是你是类型的语义:比如它如何传递给函数,是否需要使用'new'来实例化它,以及它是存储在堆栈还是堆上。即使最后一个只是implementation detail。
答案 6 :(得分:1)
或许需要更多地理解OO调用约定。
当创建一个对象时,它实际上并不复制ToString的代码,后面的对象调用是从
转换而来的。target.ToString();
到逻辑上的东西:
ToString(target);
因此,只有一个函数代码副本(每个多态实例),并且在调用方法时传入对象指针。
答案 7 :(得分:0)
所有的答案大多是正确的,但我觉得该方法属于system.object和system.valuetype,system.Int32是从它派生的。所以当你创建它的权限时,它将显示基础的方法上课。
答案 8 :(得分:0)
盒装值类型继承自object,但它们具有引用语义而不是值语义。未装箱的值类型不是对象,但在值类型和对象之间存在隐式表示更改转换。接口类型不从Object继承,但在接口类型和Object的变量/参数/字段之间存在隐式表示保留转换。请注意,泛型上的接口约束不会使泛型类型成为接口类型。如果泛型类型恰好是值类型,则从泛型类型到Object或接口类型的转换将是一种表示保留转换,即使它实现了转换类型的接口。