C# 无法获取托管类型位图scan0的地址、大小或声明指向托管类型位图scan0的指针

C# 无法获取托管类型位图scan0的地址、大小或声明指向托管类型位图scan0的指针,c#,image,C#,Image,我定义了自己的24位数据类型,如下所示 class _24bit{ public byte[] _value = new byte[3]; } 我有一个24位数据数组中的二进制数据 _24bit []data = new _24bit 我声明我的位图为 Bitmap b = new Bitmap(columns / 3, rows, PixelFormat.Format24bppRgb); 但是当我声明它以获取位图中的一行时 _24bit *row = (_24

我定义了自己的24位数据类型,如下所示

class _24bit{
        public byte[] _value = new byte[3]; 
   }
我有一个24位数据数组中的二进制数据

 _24bit  []data = new _24bit
我声明我的位图为

Bitmap b = new Bitmap(columns / 3, rows, PixelFormat.Format24bppRgb);
但是当我声明它以获取位图中的一行时

_24bit *row = (_24bit *)bmd.Scan0 + (j * bmd.Stride);
我得到这个编译错误

无法获取托管类型('mynamespace.\u 24bit')的地址、大小或声明指向该类型的指针


如何处理自己的24位数据类型?

\u 24位
是一种托管引用类型,获取指向它的指针实质上就是获取指向堆上某个非常量位置的引用的指针,这不是您想要的

\u 24位
声明为
结构
而不是
,只要它只包含非托管类型,就可以使用指针。在中有更详细的解释


你不能像Robert G.写的那样初始化结构


将您的结构放入初始化结构的类。

您确实不能声明指向托管引用类型的指针(并且您的24位类是托管引用类型)。即使将
\u 24位
声明为
结构
(使其成为值类型),它仍然包含对字节数组的引用(不是字节数组本身,只是一个使此结构的大小大于24位的引用)。您可以将数组声明为
已修复
不安全
,以修复该问题。您可能还需要指定
StructLayout
属性:

[StructLayout(LayoutKind.Sequential, Pack=1, Size=3)]
struct _24bpp
{
    public unsafe fixed byte _value[3];
}
请注意,您只能在
unsafe
上下文中访问此结构的内容。或完全删除数组声明:

[StructLayout(LayoutKind.Sequential, Pack=1, Size=3)]
struct _24bpp
{
    public byte B;
    public byte G;
    public byte R;
}
或者,您可以根据数据结构重新创建位图,并将数据从非托管内存复制到数据结构。差不多

public static _24bit[][] GetBitmapPixelsFrom24bpp(BitmapData data)
{
    if(data == null) throw new ArgumentNullException("data");

    var bitmapRows = new _24bit[rows][];
    for(int row = 0; row < data.Height; ++r)
    {
        bitmapRows[row] = new _24bit[data.Width];
        for(int pixel = 0; pixel < data.Width; ++pixel)
        {
            byte b = Marshal.ReadByte(data.Scan0, data.Stride * row + pixel * 3 + 0);
            byte g = Marshal.ReadByte(data.Scan0, data.Stride * row + pixel * 3 + 1);
            byte r = Marshal.ReadByte(data.Scan0, data.Stride * row + pixel * 3 + 2);
            var bitmapPixel = new _24bit();
            bitmapPixel._value[0] = b;
            bitmapPixel._value[1] = g;
            bitmapPixel._value[2] = r;
            bitmapRows[row][pixel] = bitmapPixel;
        }
    }
    return bitmapRows;
}
public static\u 24bit[]GetBitmapPixelsFrom24bpp(BitmapData数据)
{
如果(data==null)抛出新的ArgumentNullException(“数据”);
var bitmapRows=new _24位[rows][];
对于(int row=0;row
只需将您的类重命名为

class bmp24bit()
{
    public byte[] _value = new byte[3]; 
}

我按照你说的做了,但现在我得到了这个错误消息“不能让结构中的实例字段初始化器”C#structs的行为与C/C++结构有点不同,C#structs有一个默认构造函数,它将所有内容初始化为它的默认值,并且所有构造函数都必须从中继承。也不允许像在
\u 24bit
中那样初始化变量。因此您有两个选项,要么添加构造函数
public 24bit(byte unused):this(){{u value=new byte[3];}
,或者更好的解决方案是,用
字节r,g,b替换
\u value
。如果您仍然想使用带有#2的索引器,请使用以下命令:似乎我也完全忘记了固定数组。。。选项#3,您可以替换
公共字节_值=新字节[3]带有
公共固定字节_值[3]
我还更新了我的答案以使用第二个选项。确定顺序是b g r而不是r g b吗?是的,
Format24bppRgb
令人困惑,因为它实际上是BGR字节顺序。我想要一个行指针,这样我就可以用数据填充它,我可以用你的函数来完成吗?不,此函数仅将数据读入托管内存,不提供原始指针。您需要根据其中一个建议更改
\u 24bit
类。此函数显示了一个概念,即如何在不更改数据类型的情况下仍使用位图。
class bmp24bit()
{
    public byte[] _value = new byte[3]; 
}