为什么哦为什么不允许这样做:
import csv
read_a = csv.reader(filaA, delimiter='\t')
read_b = csv.reader(filaB, delimiter='\t')
dict_a = {tuple(row[:2]): row for row in read_a}
dict_b = {tuple(row[:2]): row for row in read_b}
shared_keys = set(dict_a) & set(dict_b) # intersection of keys
writer = csv.writer(open('file.csv', 'w'), delimiter='\t')
writer.writerows(dict_a[k] + dict_b[k] for k in shared_keys)
我收到编译错误“无法获取地址,获取大小,或声明指向托管类型('T')的指针”
或“结构”约束还不够?从某种意义上说,它仍然可以是一个托管结构?
我是否正确理解我的结构可能不会被搞砸?如果是这样,blittable应该不是一个有效的约束?
答案 0 :(得分:5)
就像Damian_The_Unbeliever所说,你不能创建托管对象或包含托管字段的结构的非托管指针。就像我在评论中所说的那样,没有可以实现的通用约束,这将确保编译时安全性,以确保结构符合这些要求。因此,您无法指向泛型类型。
然而,可能有一种解决方法。 Marshal.StructureToPtr
方法将获取结构对象并将其数据复制到IntPtr
地址。您可以将其与Marshall.AllocHGlobal
结合使用,以实现所需的功能:
private static byte[] ConvertStruct<T>(ref T str) where T : struct
{
int size = Marshal.SizeOf(str);
IntPtr arrPtr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, arrPtr, true);
var arr = new byte[size];
Marshal.Copy(arrPtr, arr, 0, size);
Marshal.FreeHGlobal(arrPtr);
return arr;
}
正如Kris Vandermotten指出的那样,Marshal.AllocHGlobal
实际上并不是必需的。您可以固定数组,为其获取IntPtr
,然后直接复制到IntPtr
:
private static unsafe byte[] ConvertStruct<T>(ref T str) where T : struct
{
int size = Marshal.SizeOf(str);
var arr = new byte[size];
fixed (byte* arrPtr = arr)
{
Marshal.StructureToPtr(str, (IntPtr)arrPtr, true);
}
return arr;
}
第一种方法的好处是,它不需要unsafe
上下文才能工作。 (如果你关心那种事情。)
答案 1 :(得分:3)
来自C#Spec,第18.2节:
不允许指针指向引用或包含引用的结构,指针的引用类型必须是非托管类型。
...
非托管类型是以下之一:
•
sbyte
,byte
,short
,ushort
,int
,uint
,long
,{{1} },ulong
,char
,float
,double
或decimal
。•任何枚举类型。
•任何指针类型。
•任何用户定义的 struct-type ,它不是构造类型,只包含 unmanaged-types 字段。
并且没有真正的方式通过通用约束来表达这一点。即使这个定义看起来与"blittable"的任何定义基本相似,但值得注意的是,在C#规范中没有定义(甚至引用)该特定概念。例如,从MSDN页面我们可以看到&#34; blittable类型的一维数组&#34;是blittable,但上面的规范定义似乎排除了数组。
答案 2 :(得分:1)
尝试这样的事情。通过编组,您可以避免使用不安全的关键字
private static byte[] ConvertStruct<T>(T str) where T : struct
{
int size = Marshal.SizeOf(str);//sizeof
int ptr = (int)Marshal.AllocCoTaskMem(size);//allocate memory before past the structure there
Marshal.StructureToPtr(str, (IntPtr)ptr, true);//alloc your structure
byte[] res=new byte[size];//your result
for (int i = 0; i < size; i++)
{
res[i] = Marshal.ReadByte((IntPtr)ptr);//read byte from memory
ptr++;//offset
}
return res;
}
此外,您需要在结构中设置StructLayout属性,如下所示
[StructLayout(LayoutKind.Sequential)]
[Serializable]
public struct StrStruct
{}
如果您的结构包含具有umnmanaged类型的字段,请使用MarshalAs属性来正确编组所有字段和未映射类型(例如,字符串作为LPWStr)。如果您的结构完全不受管理,则需要使用MarshalAs编组其所有字段。