.NET 类型(Types)的那么些事

引言

您是.Net工程师?那 .NetFramework中的类型您掌握有三大类吗?(除了引用类型和值类型,还有?)

引用类型一定在“堆”上,值类型一定在“栈”上?

那引用类型在内部存款和储蓄器中的布局细节你又亮堂有个别了?

 

.Net Framework 中的Types分类

 

图片 1

C# type categorization. 带阴影的都是 C# 的内建项目首要字.

除了objectand string(分别为System.Object 和``System.String别名),
其余带阴影的都以不难的值类型.

上面是摘自《C#语言专业5.0》 –> 4.类型(page:77)

C# 语言的类别划分为两大类:值类型 (Value type) 和引用类型 (reference
type)。

其三种档次是指针,只能用在不安全代码中。

引用类型和值类型在内部存款和储蓄器中怎么样分配的吧?

那壹块我们将经过一小段代码来讲学,在上课前让大家回看下

引用类型 和值类型的赋值进度中在内部存款和储蓄器处理上的分别:

  • 把3个值类型a(定义如下int a=80;)赋给其余1个值类型b(int
    b;),即(b=a;)时,会把a的值拷贝一份给a,如下图;

图片 2

  • 把二个引用类型a(定义如下Employee a=new
    employee();)赋给别的一个引用类型b(Employee
    b;),即(b=a;)时,会把a的地址(引用)拷贝1份给a,即他们本着同三个地点;

图片 3

起来代码讲解,首先看代码如下:

Form myForm = new Form();
Size s = new Size (100, 100);          // struct = value type
Font f = new Font (“Arial”,10);        // class = reference type
myForm.Size = s;
myForm.Font = f;

瞩目代码中
myForm.Size中的Size和myForm.Font的Font是Form类型的性子(Property)不是类别(class
type,代表有些项目)。

在.NetFramework中如此的应用办法最佳广泛,初学者不要混淆了那两者。

教师代码前给我们再提下知识点:

  • Size是Struct类型,当然就是值类型(ValueType)
  • Font是Class类型,当然正是引用类型(ReferenceType)

 

上边那段代码的内部存款和储蓄器中的分配,示意图:

图片 4

很清楚地来看

  • Size类型的s分配到了Stack上,而Front类型的f 和Form类型的myForm则分配在堆上。
  • 与此同时myForm的Font属性引用到了Font类型f。
  • myForm的Size属性有它自个儿的值(Width和Height),它是Size类型s的三个拷贝。

这边大家更清楚的收看了值类型和引用类型在值赋值进程中的分裂

小编们可以透过修改Font类型f的值,来修改myForm中的字体样式,但无法通过修改s来修改myFrom的Size。

引用类型的Object内存布局基础结构

图片 5

地方这些图体现的构造是经过分析源码得出的:

  1. 首先ObjectHeader(在其所在的AppDomain中的那个Thread通过调用Monitor.Enter锁了这几个目的)
  2. 接下去是Method Table
    指针(该指针指向AppDomain中宣示(定义)托管类型),借使程序集被加载到AppDomain
    neutral 中,那么富有的AppDomain中该类型实例的Method
    Table指针都一点差距也没有。CLGL450类型系统的该基础营造块在托管代码中都是可视的。(TypeHandle.Value
    是三个IntPtr.aspx))
  3. 最后正是那有的正是该品种实例的值。

CL罗布ject的那些实例对象的地点在废品回收时也有非常的大希望会生出变动。(实际参看GC中审核消减进度)

 

\sscli20\clr\src\vm\object.h

//
// The generational GC requires that every object be at least 12 bytes
// in size.   
#define MIN_OBJECT_SIZE     (2*sizeof(BYTE*) + sizeof(ObjHeader))

A .NET object has basically this layout:

class Object
{
  protected:
    MethodTable*    m_pMethTab;

};

class ObjHeader
{
  private:
    // !!! Notice: m_SyncBlockValue *MUST* be the last field in ObjHeader.
    DWORD  m_SyncBlockValue;      // the Index and the Bits
};
Platform 最小实例大小(bytes)
x86 12 bytes = 2*4+4
x64 24 bytes = 2*8+8

 

引用类型的Object内部存款和储蓄器布局代表性结构

 

常见对象

 

图片 6

数组对象 – Array

图片 7

字符串对象

图片 8

 

Boxing,小心你的值类型不经意间棉被服装箱

 

int a=1;
object b=a;

那段代码大家都知道会生出装箱,装箱后本来的值类型会有啥样变化?看下装箱和拆箱的手续:

装箱:
对值类型在堆中分红三个对象实例,并将该值复制到新的对象中。按三步进行。
第二步:新分配托管堆内部存款和储蓄器(大小为值类型实例大小加上3个主意表指针和一个SyncBlockIndex)。
第2步:将值类型的实例字段拷贝到新分配的内部存款和储蓄器中。
其三步:重回托管堆中新分配对象的地方。那几个地点正是贰个对准对象的引用了。
有人如此驾驭:假诺将Int3二装箱,重临的地方,指向的便是一个Int3二。小编觉得也不是不能够这么敞亮,但那真的又反常,一来它不健全,②来指向Int3贰并没说出它的实质(在托管堆中)。
拆箱:
反省对象实例,确定保障它是给定值类型的四个装箱值。将该值从实例复制到值类型变量中。
有书上讲,拆箱只是收获引用对象中指向值类型部分的指针,而内容拷贝则是赋值语句之触发。小编以为这并不急急。最要害的是检核对象实例的原形,拆箱和装箱的连串必需匹配,这点上,在IL层上,看不出原理何在,作者的预计,只怕是调用了看似GetType之类的办法来取出类型实行匹配(因为急需从严匹配)。

那么给你个自定义结构体,你还精晓哪些状态会棉被服装箱吗?

参考《严防装箱落到实处到底,只做2/四也是没戏

附加

为便利我们查看源码,那里提供1个源码索引表

SSCLI文件目录

Item SSCLI Path
AppDomain \sscli\clr\src\vm\appdomain.hpp
AppDomainStringLiteralMap \sscli\clr\src\vm\stringliteralmap.h
BaseDomain \sscli\clr\src\vm\appdomain.hpp
ClassLoader \sscli\clr\src\vm\clsload.hpp
EEClass \sscli\clr\src\vm\class.h
FieldDescs \sscli\clr\src\vm\field.h
GCHeap \sscli\clr\src\vm\gc.h
GlobalStringLiteralMap \sscli\clr\src\vm\stringliteralmap.h
HandleTable \sscli\clr\src\vm\handletable.h
InterfaceVTableMapMgr \sscli\clr\src\vm\appdomain.hpp
Large Object Heap \sscli\clr\src\vm\gc.h
LayoutKind \sscli\clr\src\bcl\system\runtime\interopservices\layoutkind.cs
LoaderHeaps \sscli\clr\src\inc\utilcode.h
MethodDescs \sscli\clr\src\vm\method.hpp
MethodTables \sscli\clr\src\vm\class.h
OBJECTREF \sscli\clr\src\vm\typehandle.h
SecurityContext \sscli\clr\src\vm\security.h
SecurityDescriptor \sscli\clr\src\vm\security.h
SharedDomain \sscli\clr\src\vm\appdomain.hpp
StructLayoutAttribute \sscli\clr\src\bcl\system\runtime\interopservices\attributes.cs
SyncTableEntry \sscli\clr\src\vm\syncblk.h
System namespace \sscli\clr\src\bcl\system
SystemDomain \sscli\clr\src\vm\appdomain.hpp
TypeHandle \sscli\clr\src\vm\typehandle.h

越来越多源码参考http://www.projky.com/dotnet

参考

 

The Truth About .NET Objects And Sharing Them Between
AppDomains

Six important .NET concepts: Stack, heap, value types, reference types,
boxing, and
unboxing

Shared Source Common Language
Infrastructure

[翻译经典作品]深切.NET Framework内部,
看看CL奥迪Q5怎么着创设运营时对象的

.NET对象的内部存款和储蓄器布局

托管堆与废物收集

C#
装箱和拆箱[整理]

mdsn 类型详解(Jit and
Run)