C#如何识别引用的真实类型(一)——转载

简介: 知识储备,如果您已经十分熟习这些,可以跳过 1 什么是引用?  引用是一个数据结构,包含了一个计算机内存堆地址的值,就类似C++中的指针一样,本文中所有出现有关"引用"字句,读者都可以把它理解成C,C++中的指针   再说一遍,引用 与 指针 是不同的,例如 GC在回收内存的时候,会修改引用的值,.

知识储备,如果您已经十分熟习这些,可以跳过

1 什么是引用?

 引用是一个数据结构,包含了一个计算机内存堆地址的值,就类似C++中的指针一样,本文中所有出现有关"引用"字句,读者都可以把它理解成C,C++中的指针

  再说一遍,引用 与 指针 是不同的,例如 GC在回收内存的时候,会修改引用的值,但本文的重点并不是讲述 引用 与 指针的差别,所以,读者可以把所有在这里出现的 "引用" 理解成 c,c++ 中的指针

2 栈 与 堆, .net中的内存分配?

  http://blog.csdn.net/cuike519/archive/2009/12/23/5063333.aspx ,如果你还不是很清楚这些,这里有你所需要了解的

方法是类的,非静态字段是实例的


  类中的方法(无论是静态的,还是非静态的)本质上都是属于类的,类中非静态的字段,是属于类的实例的

  正是因为这一点的不同,类中的方法代码只创建了一份在内存中,而类中的非静态字段是随着类的实例创建而创建的

  理论上 ,实例一个类的对象,只需要在内存中分配 与 类中所有非静态字段总和大小 一致的内存就可以了

  然后把分配的堆中内存地址的首地址 赋给 栈 中的引用

  但,实际情况并非如此简单,在.net 中,当实例化一个类的时候, 总共分配了( sizeof(void*) + 类中所有非静态字段大小总和 )  的内存

  那么,那多出的 sizeof(void*) 是用来做什么的呢?

P.S.  如果我没有记错的话 在32位的CPU下, sizeof(void*) 的大小是4个字节

那多出来的4字节,是做什么的呢?

 引用指向了一个内存地址,在该地址 + sizeof(void*) 后便紧跟着实例的非静态字段

 每个类都拥有 sizeof(void*) 大小的"多余"内存,那么在那里面,究竟有什么呢?

 在那里面,总共有两个东西

 第一个是名为 syncblock 的索引

 第二个是指向一个为公开的数据结构的句柄

 不要小看那个未公开的数据结构,那里有实际类型的相关数据,.net正是依靠它来准确识别引用的真实类型,就算你按照以下的例子做,CLR也会知道,谁到底是谁

  Subclass sub = new Subclass();

  BassClass B = (BassClass)sub;

  B.GetType(); // CLR说,别装B了,我知道你是 subclass 类的实例

真像已经大白,还想要知道更多?

  

   1, 那个未公开的数据结构,有一个名字,叫做 CORINFO_CLASS_STRUCT(这个名字只是做参考,实际中,也许并不是这个名字),我们无法使用编程的方法直接访问这个数据结构,但是.net提供了一个类, System.RuntimeTypeHandle 允许我们用已经定义好的方法,访问它

  有关 System.RuntimeTypeHandle 的更多信息,请参照MSDN

   

   2, MSIL提供了两个进行类型间相互转换的IL指令

    isinst

    castclass

    这两个指令在编译成本机代码的时候,都会产生访问 CORINFO_CLASS_STRUCT以验证是否可以进行转换

    它们唯一的不同是当验证失败时,castclass 抛出一个 System.InvalidCastException异常 (很熟习吧?)

    isint 则会将一个为 null 的引用添加到栈顶 (MSIL是一门基于栈的语言,有兴趣的童鞋,可以google下 :-))

    在C#中

    as ,is 操作符 被转换成 isinst

   

     () 强制类型转换符 被转换成     castclass





原文发布时间为:2010-03-19



本文来自云栖社区合作伙伴CSDN博客,了解相关信息可以关注CSDN博客。

目录
相关文章
|
6月前
|
存储 安全 编译器
C# 11.0中的泛型属性:类型安全的新篇章
【1月更文挑战第23天】C# 11.0引入了泛型属性的概念,这一新特性为开发者提供了更高级别的类型安全性和灵活性。本文将详细探讨C# 11.0中泛型属性的工作原理、使用场景以及它们对现有编程模式的改进。通过深入了解泛型属性,开发者将能够编写更加健壮、可维护的代码,并充分利用C#语言的最新发展。
|
编译器 C#
C#之十七 局部类型
C#之十七 局部类型
33 0
|
21天前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
30 3
|
20天前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
37 1
|
19天前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
11 0
|
1月前
|
C#
C# 可空类型(Nullable)
C# 单问号 ? 与 双问号 ??
46 12
|
3月前
|
存储 C#
揭秘C#.Net编程秘宝:结构体类型Struct,让你的数据结构秒变高效战斗机,编程界的新星就是你!
【8月更文挑战第4天】在C#编程中,结构体(`struct`)是一种整合多种数据类型的复合数据类型。与类不同,结构体是值类型,意味着数据被直接复制而非引用。这使其适合表示小型、固定的数据结构如点坐标。结构体默认私有成员且不可变,除非明确指定。通过`struct`关键字定义,可以包含字段、构造函数及方法。例如,定义一个表示二维点的结构体,并实现计算距离原点的方法。使用时如同普通类型,可通过实例化并调用其成员。设计时推荐保持结构体不可变以避免副作用,并注意装箱拆箱可能导致的性能影响。掌握结构体有助于构建高效的应用程序。
115 7
|
3月前
|
程序员 C#
C# 语言类型全解
C# 语言类型全解
25 0
|
3月前
|
开发框架 .NET 编译器
C# 中的记录(record)类型和类(class)类型对比总结
C# 中的记录(record)类型和类(class)类型对比总结
|
3月前
|
传感器 开发框架 JSON
聊聊 C# dynamic 类型,并分享一个将 dynamic 类型变量转为其它类型的技巧和实例
聊聊 C# dynamic 类型,并分享一个将 dynamic 类型变量转为其它类型的技巧和实例
160 0