sizeof(T)

从C++的模板代码往C#代码移植的时候发现了一个小问题。

在C++模板代码中 sizeof(T)是一种有效的写法,最终在会编译器展开成sizeof(int),sizeof(float)或者sizeof(myclass),然后在运行时这个代码是有效的,能够执行的。于是我们看上去就可以计算在运行时计算T的大小,并分配内存。

但是在C#的泛型代码中,sizeof(T)无法编译过的,因为无法确认T是什么的情况下,T的大小是无法计算的,于是C#编译器是不认的。

按C#提供的规范,sizeof只能在不安全的代码中使用,操作的参数是非托管类型。

# 非托管类型

sbyte、byte、short、ushort、int、uint、long、ulong、

char、float、double、decimal 或 bool

任何枚举类型任何指针类型任何用户定义的 struct 类型,只包含非托管类型的字段,并且在 C# 7.3

及更早版本中,不是构造类型(包含至少一个类型参数的类型)

那么在C#的泛型类里面,该如何进行sizeof(T)操作?

然后我开始尝试着在.net的开源代码里面寻找答案

OK,一下子找到两个Unsafe.SizeOf和Marshal.SizeOf

Unsafe.SizeOf

Unsafe.SizeOf 属于 CompilerServices,继续挖掘代码,最后得到了一段IL Code

 .method public hidebysig static int32 SizeOf<T>()

                            cil managed aggressiveinlining

   {         //....         .maxstack 1         sizeof !!T         ret   } // end of method Unsafe::SizeOf

OK,这是 IL语言,我们就看自己关心的sizeof

 #IL Code 说明sizeof 

将提供的值类型的大小(以字节为单位)推送到计算堆栈上。

OK,UnsafeSizeOf只有值类型的大小

Unsafe.SizeOf<myclass>();

不管我怎么改变myclass的内容,结果都是8,所以,这个不能随便用,只能用在值类型上了。

结合C#的文档,我蛮怀疑关键字sizeof要么是调用了Unsafe.Sizeof函数,要么就是直接转换成了IL Code的sizeof。但没什么依据,我没在.net的源代码里找到这一点。

Marshal.SizeOf

这个属于 System.Runtime.InteropServices,是.net 和COM互操作的时候用的。

这个函数挖掘代码之后是到了一些cpp代码,基本路径是这样的

Marshal.SizeOf->SizeOfHelper->            MarshalNative::SizeOfClass->GetNativeSize()

Marshal.SizeOf->SizeOfHelper是C#代码

GetNativeSize()是用C++代码实现的,两边怎么焊接的我就不管了,这个暂时不关心。

最后

 BOOL GetNativeSize() const {         LIMITED_METHOD_CONTRACT;         return m_cbNativeSize; }

返回了一个m_cbNativeSize;

OK,我们实际测试下

Marshal.SizeOf<myclass>();

直接报错了,因为不是一个非托管结构,没法计算大小。

Type 'ConsoleApp1.Program+myclass' cannot be marshaled as an unmanaged structure; no meaningful size

or offset can be computed.

OK,稍微调整下代码

加一个[StructLayout(LayoutKind.Sequential)]

然后输出结果是12,刚好是三个int的大小。

等下,还有第三种办法:从 C# 7.3 开始,可使用 unmanaged 约束指定:类型参数为“非指针、不可为 null 的非托管类型”。从 C# 8.0 开始,仅包含非托管类型的字段的构造结构类型也是非托管类型,如以下示例所示:

public struct Coords<T>{    public T X;    public T Y; }

 public class UnmanagedTypes {    public static void Main()    {        DisplaySize<Coords<int>>();        DisplaySize<Coords<double>>();    }

    private unsafe static void DisplaySize<T>() where T : unmanaged    {        Console.WriteLine($"{typeof(T)} is unmanaged and its size is {sizeof(T)} bytes");    } } // Output: // Coords`1[System.Int32] is unmanaged and its size is 8 bytes // Coords`1[System.Double] is unmanaged and its size is 16 bytes

那么回到我开始的问题,如果都是值类型,两个都可以用,如果是自定义类,用Marshal.SizeOf就可以了

或者把泛型类写成

public struct Coords<T>

                where T : unmanaged

{    public T X;    public T Y;}

即T只限于非托管类型。

结论

1.值类型泛型类,可以用

where T : unmanaged 和sizeof(T)配合使用或者直接使用 Unsafe.Sizeof(T)

2.非值类型泛型类,可用

Marshal.SizeOf(T)

本文结束。

------------------------------

写在文后:昨天发出之后发现把“泛”字打成范了,想想还是删除了今天再发,写一篇技术文章从选题,写稿,编辑,检查错别字,修改,到发稿来来回回几个小时。没有一件事情是容易的。我尽量严肃对待这一切,让各位关注者能有所得。谢谢。

------------------------------

写多不如写精!

我是丁长老,欢迎关注我的技术公众号。

个人微信号nine-ding,欢迎加我微信。

如需转发文章请加微信号获取转发授权

C++模版和C#泛型求同存异录(一)sizeof(T)相关推荐

  1. typedef struct 先声明后定义_C++模版和C#泛型求同存异录(二)typedef

    (这篇文章有些复杂,请来回慢慢看) typedef C++语言中的typedef简直是个神奇的关键字,它的最简单的作用就是把一种类型重新命名,定义个别名.很像宏定义,但又不是.在编程中使用typede ...

  2. c# getresponsestream返回byte[]_C++模版和C#范型求同存异录(一)sizeof(T)

    sizeof(T) 从C++的模板代码往C#代码移植的时候发现了一个小问题. 在C++模板代码中 sizeof(T)是一种有效的写法,最终在会编译器展开成sizeof(int),sizeof(floa ...

  3. c语言泛型swap函数,C 语言实现泛型 swap 函数

    由于C语言是强类型语言,所以通常我们在编写一些函数的时候就需要指定函数的类型.这就会导致同样的函数行为因为处理的类型不同,就可能需要为不同的类型编写不同的函数版本. 比如用于交换两个变量值的如swap ...

  4. Code Project精彩系列(转)

    Applications Crafting a C# forms Editor From scratch http://www.codeproject.com/csharp/SharpFormEdit ...

  5. Code Project精彩系列(2)

    Windows Forms Fireball Resourcer 把各种资源嵌入应用程序资源 Window Hiding with C# 隐藏窗体, 似乎是其它运行的窗体 J Proper Threa ...

  6. codeproject资源集合贴

    Applications Crafting a C# forms Editor From scratch http://www.codeproject.com/csharp/SharpFormEdit ...

  7. Code Project精彩系列

    Applications Crafting a C# forms Editor From scratch http://www.codeproject.com/csharp/SharpFormEdit ...

  8. Code Project精彩系列二

    Applications Crafting a C# forms Editor From scratch http://www.codeproject.com/csharp/SharpFormEdit ...

  9. Code Project

    Applications Crafting a C# forms Editor From scratch http://www.codeproject.com/csharp/SharpFormEdit ...

最新文章

  1. hdu1.3.5 排列2
  2. linux dup用法,Unix_Linux
  3. cacti + nagios + npc 整合部署
  4. Java中,为什么子类的构造方法中必须调父类的构造方法?
  5. MySQL优化的一些基础
  6. https跳转到http session丢失问题
  7. latex python_怎么在 LaTeX 中排版 Python 代码?
  8. 大数据信息安全需要准备哪些工具
  9. 成员变量的隐藏,方法的覆盖,super关键字
  10. [UE4]增加机器人
  11. Runtime之消息转发
  12. 各 Delphi 历史版本下载合集
  13. java libtorrent_[转载]libtorrent安装windows版
  14. Ubutu 12.04LTS 安装搜狗拼音输入法+搜狗皮肤 步骤详解
  15. BMFont 制作字体时,无法导入图片
  16. 圆锥螺旋线matlab 画,圆锥螺旋线 - calculus的日志 - 网易博客
  17. Sprite和Texture的区别
  18. 论文精读:MobileNetV2: Inverted Residuals and Linear Bottlenecks
  19. mysql生成序列_mysql 自动生成编号函数
  20. 对 Linux 初级、中级、高级用户非常有用的 60 个命令

热门文章

  1. USING HAVING
  2. Android 开发学习资源
  3. ccleaner无法更新_CCleaner正在静默更新关闭自动更新的用户
  4. 将不确定变为确定~老赵写的CodeTimer是代码性能测试的利器
  5. JavaScript中“javascript:void(0) ”是什么意思
  6. 关于异或的一些东西和应用
  7. windows下编译firefox
  8. zendframework配置篇
  9. windows server 2012 dhcp 配置故障转移
  10. 无符号数、有符号数、补码在汇编中的运用及相关注意事项