为什么是可折叠的<;T>;C#7.2中的类是如何定义的?
我知道,为什么是可折叠的<;T>;C#7.2中的类是如何定义的?,c#,.net,clr,cil,c#-7.2,C#,.net,Clr,Cil,C# 7.2,我知道,Pinnable是新的Unsafe类中的方法使用的一个内部类,它不打算在该类之外的任何地方使用。这个问题不是关于一些实用的东西,但它只是为了理解为什么它被设计成这样,并学习更多关于这种语言及其各种“技巧”的知识 总而言之,定义了Pinnable类,如下所示: [StructLayout(LayoutKind.Sequential)] internal sealed class Pinnable<T> { public T Data; } [StructLayout(
Pinnable
是新的Unsafe
类中的方法使用的一个内部类,它不打算在该类之外的任何地方使用。这个问题不是关于一些实用的东西,但它只是为了理解为什么它被设计成这样,并学习更多关于这种语言及其各种“技巧”的知识
总而言之,定义了Pinnable
类,如下所示:
[StructLayout(LayoutKind.Sequential)]
internal sealed class Pinnable<T>
{
public T Data;
}
[StructLayout(LayoutKind.Sequential)]
内密封类可钉扎
{
公共数据;
}
它主要用于Span.DangerousCreate
方法中:
publicstaticspan创建(objectobj,reft objectData,int-length)
{
可折叠可折叠=不安全的As(obj);
IntPtr byteOffset=Unsafe.byteOffset(ref pinnable.Data,ref objectData);
返回新跨距(pinnable、byteOffset、length);
}
Pinnable
的原因是它用于跟踪原始对象,以防Span
实例是由一个实例(而不是本机指针)创建的
ref t
和不安全。因为(ref t)
的工作原理相同),那么Pinnable
类成为泛型类是否有具体原因?DotNetCross最初的设计实际上有一个Pinnable
类,只有一个字节
字段,它的工作原理是一样的。除了在编写/读取/返回引用时避免强制转换引用时间之外,在这种情况下使用泛型类是否有其他优势unsafe.As
执行此unsafe cast之外,还有其他方法获取对对象的引用(我指的是对对象内容的引用,否则它将与类类型的任何变量相同)吗?我的意思是,任何获得对象引用的方法(首先应该基本上具有实际对象变量的相同地址,对吗?)都不必通过自定义的二级类[StructLayout(LayoutKind.Sequential)]
中的结构并不意味着它仅对结构有效,它意味着内存中字段的实际结构的布局,无论是在类中还是在值类型中。这控制数据的实际运行时布局,而不仅仅是类型封送到非托管代码的方式。顺序存储非常重要,因为如果没有顺序存储,运行时可以随意存储内存,这意味着数据之前可能会有一些填充
T
与另一个T
的偏移量来表示T
比用字节的偏移量来表示要好。第一个字段的类型可能在其实际地址中起作用,即使该类型标记为LayoutKind.Sequential
锁)和指向方法表的指针(也称为对象类型)的头开始。在32位上,头是8字节,但实际指针指向方法表的指针(出于性能原因,获取类型比锁定对象更频繁)
因此,获取指向数据开头的指针的一种不可移植的方法是将对象引用强制转换为指针并向其添加4个字节。第一个字段应该从这里开始
我能想到的另一种方法是利用。它通常用于访问数组或字符串数据,但也适用于其他对象:
[StructLayout(LayoutKind.Sequential)]
class Obj
{
public int A;
}
var obj = new Obj();
var gc = GCHandle.Alloc(obj, GCHandleType.Pinned);
IntPtr interior = gc.AddrOfPinnedObject();
Marshal.WriteInt32(interior, 0, 16);
Console.WriteLine(obj.A);
我认为这实际上是非常可移植的,但仍然需要固定对象(GCHandle中定义了InternalAddRofPindedObject,但即使这没有检查句柄是否实际固定,如果在非固定对象上使用,返回值可能无效)
尽管如此,Span使用的技术似乎是实现这一点的最方便的方法,因为许多底层工作都是在纯CIL(如参考算术)中完成的
Pinnable
是默认使用LayoutKind.Auto
的类(引用类型)<代码>顺序默认用于值类型(结构)。这就是为Pinnable
指定布局的原因。请参阅中的备注部分。@YohDeadfall谢谢,我没有注意到有关使用该属性的类的详细信息!我已经编辑了问题,并将此信息添加到第二点。我不完全确定为什么需要这个属性,因为Span
并没有显式地传递给非托管代码(我想,您是否可以修复它,获取一个指针并传递它?),但至少这个属性现在是有意义的,感谢详细的回答,即使pinted
类的通用位仍然不是100%清楚,所有其他的都变得更有意义了,干杯!
[StructLayout(LayoutKind.Sequential)]
class Obj
{
public int A;
}
var obj = new Obj();
var gc = GCHandle.Alloc(obj, GCHandleType.Pinned);
IntPtr interior = gc.AddrOfPinnedObject();
Marshal.WriteInt32(interior, 0, 16);
Console.WriteLine(obj.A);