在《C#高级编程》第6版中说:
int i = 6;
实际是为i分配了一个4字节的空间来存储6这个值,而在MSDN中说int其实是System.Int32的一个别名,而System.Int32的定义又为Public struct Int32{},说明int实际上是一个结构体(其中覆盖了很多Object方法),那么int i 到底是分配了4字节的空间,还是一个struct Int32该有的空间?在按值传递参数时,到底是复制这个6(四字节),还是一个struct副本?
另外,i.ToString()这个方法的调用,查看IL中间代码,发现并没有进行装箱操作,也就是说i.ToString()是调用System.Int32 (struct)中的一个方法,如果i只是堆栈上一个4字节的值,那它在没有进行装箱的情况下,是怎样转到System.Int32中的方法去的?如果i是一个Struct,是不是很浪费内存?
最后,Struct是怎样隐式继承于System.Object的?
int i = 6;
实际是为i分配了一个4字节的空间来存储6这个值,而在MSDN中说int其实是System.Int32的一个别名,而System.Int32的定义又为Public struct Int32{},说明int实际上是一个结构体(其中覆盖了很多Object方法),那么int i 到底是分配了4字节的空间,还是一个struct Int32该有的空间?在按值传递参数时,到底是复制这个6(四字节),还是一个struct副本?
另外,i.ToString()这个方法的调用,查看IL中间代码,发现并没有进行装箱操作,也就是说i.ToString()是调用System.Int32 (struct)中的一个方法,如果i只是堆栈上一个4字节的值,那它在没有进行装箱的情况下,是怎样转到System.Int32中的方法去的?如果i是一个Struct,是不是很浪费内存?
最后,Struct是怎样隐式继承于System.Object的?
第2章介绍了所有类型,包括简单的预定义类型,例如int和char,以及复杂类型,例如从Object类型中派生的类和结构。下面可以像处理对象那样处理字面值:string s = 10.ToString(); 但是,C#数据类型可以分为在堆栈上分配内存的值类型和在堆上分配内存的引用类型。如果int不过是堆栈上一个4字节的值,该如何在它上面调用方法?C#的实现方式是通过一个有点魔术性的方式,即装箱(boxing)。但是查看该句的IL代码,发现并没有box [mscorlib]System.Int32 而是 call instance string [mscorlib]System.Int32::ToString()
另外,假如有个函数SomeFunction(int j); int i = 10; SomeFunction(i); 传递给SomeFunction是一个4字节的值还是一个struct?
关键没有看到进行装箱操作,它是怎么调用Struct方法?
Console.WriteLine("{0}", sizeof(Int32));
都是4
struct Int32 不可能就4个字节,因为struct Int32中还包含了其他许多方法
都看了两天MSDN啦,都是说一些重复的话,哪些是值类型,哪些是引用类型,值类型分配在堆栈上之类。
就算Int32重写了四个ToString(),但是还是没有解释是怎样调用这些方法上来,我怀疑call instance string [mscorlib]System.Int32::ToString()这也是不是一种装箱行为?
方法不占实例空间?MSDN中哪里有介绍?对内存分配这块很不熟
不管有多少个Int32对象,保存的方法都只有一个公用,因为代码都一样
不可能每个对象都单独用空间保存方法的
int 型是 C# 的内置类型,System.Int32是.net库类型。如果你在.net平台下开发的话,VS 会将所有的int都译为.net的类型 System.Int32。它在内存的长度为 4 字节,这是没有问题的。至于你觉得 struct System.Int32 是一种浪费空间的做法,我觉得吧……你的程序基础……不太好……struct 只是一种语言标识,在内存中,它该是多长,就是多长,如下定义:struct _MyInt {
int a;
};这个 _MyInt 的 Struct 类型和 int 型是一样大小的,没有区别。而 struct 可定义成员函数,而那些成员函数在内存中是进代码区的,与堆栈无关,值可是存在栈空间里面的。程序的各部分在内存中的空间分配,你了解吧……不了解的话……复习一下C语言吧……对 int 或者 System.Int32 的数据操作, C# 视为值类型操作,其表现与值一样,值类型对像之间进行操作的时候,根本就没有 boxing 和 unboxing 的问题。这些MSDN上都有,可能看得还是不够细,给你提个醒,MSDN上有着更全面的介绍。你要相信MSDN上没有你查不到的东西。
int i = 10;
Console.WirteLint("i: {0}", i); // 装箱
Console.WirteLint("i: {0}", i.ToString()); // 性能要比上句好,因为没有进行装箱
那是你没查到。里面有的是各种概念的overview。
静态函数跟成员函数本质上是一致的,仅是编译器会在成员函数的参数列表最后,隐式地添加一个参数 "this",这样就可以正确地找到对应的实例。
int 是 struct Int32的一个关键字别名
short 是 struct Int16的一个关键字别名
long 是 struct Int64的一个关键字别名自己编程的时候,直接转int/short 定义都能知道很多东西......
我的回答是,一个struct副本。因为struct是值类型。值类型在初始化的时候,肯定会将需要的内存都初始化成0(和C、C++一样).所以无论你的struct里面是几个对象都会被优先初始化为0。当然存放的位置,我可以告诉你是线程堆栈里。i.ToString()这个方法的调用,查看IL中间代码,发现并没有进行装箱操作,也就是说i.ToString()是调用System.Int32 (struct)中的一个方法,如果i只是堆栈上一个4字节的值,那它在没有进行装箱的情况下,是怎样转到System.Int32中的方法去的?
我的回答,首先值类型都是从System.ValueType继承的,而toString()是个虚方法。显然我调查了下,仔细查看了Int32.toString()方法后发现,这是一个重写方法,也就是说它是以非虚的方式调用的。所以就不存在所谓的装箱操作,编译器是直接通过方法内的代码直接调用的。我们可以看到如下代码:public override string ToString()
{
return Number.FormatInt32(this, null, NumberFormatInfo.CurrentInfo);
}[MethodImpl(MethodImplOptions.InternalCall)]
public static extern string FormatInt32(int value, string format, NumberFormatInfo info);
他显然调用了某个对象的静态方法完成的转换。而且还是CLR的内部调用。这个不管,但是从理论上来说调用一个虚方法,CLR需要判断对象的类型,是以定位类型的方法表来查询的,但是对于一个未装箱的值类型,根本就不存在所谓的“类型对象指针”。所以呢就会出现上面的处理方法。如果i是一个Struct,是不是很浪费内存?
我的回答是,绝对省内存。因为值类型在不复制的情况下,占用的堆栈大小绝对要比引用类型占用托管堆来的少。如果说你要是吧i放到一个class里,那么我告诉你,在托管堆里将不是一个对象而是3个对象。一个是i的本身,另一个是类型对象指针,还有一个是同步索引块。当然如果你没事反复复制Struct的话,那我说你还不如使用class,因为class作为引用类型一般情况下只会是占用托管堆中的一块地方,然后把地址传递给托管堆栈。所以如果说你实例化一个以后,再实例化一个相同的对象,则会指向同一块内存地址。