结构数组中的 C# 数组丢失内容



在长时间的C++和Qt之后,我只是回到了C#。我目前被我认为非常简单的问题难倒了。

我有一个结构:

struct FontGlyph {
public uint codepoint;
public byte[] bmp;
...
}

以及一系列这样的结构:

FontGlyph[] glyphs = new FontGlyph[100];

现在,我有几个函数可以设置和修改结构中的字段:

static void ConvertFont(Font fnt) {
...
if (fnt.IsSpaceCharacter) {
glyphs[idx].codepoint = 0x00FF;
glyphs[idx].bmp = null;
}
else {
RenderFontGlyph(glyphs[idx]);
// glyphs[idx].bmp is NOT ok here - it is null!
}
...
}
static void RenderFontGlyph(FontGlyph glyph) {
...
glyph.bmp = new byte[256];
// bmp is fine here, and can be populated as a normal array
...
} 

这不是一个特别好的代码片段,但是,在 RenderFontGlyph 函数中,我可以看到bmp数组被正确分配,但当 RenderFontGlyph 函数返回时,在检查glyphs[idx]变量时,bmp回到 null。

我很感激我可能正在做一些 n00bish 的事情,但已经有一段时间了。我是垃圾收集的受害者还是愚蠢?我突然想到,该结构被传递到RenderFontGlyph函数 by-value 而不是 by-ref 中,但这也没有区别!

我突然想到该结构被传递到 RenderFontGlyph 函数 by-value 而不是 by-ref 中,但这也没有区别!

嗯,是的,确实如此。您正在创建结构的副本,并将其传递给RenderFontGlyph。对该副本所做的任何更改都不会影响其他任何内容。

如果改为通过引用传递它,它将有所不同,因为您将修改数组中的原始存储位置:

RenderFontGlyph(ref glyphs[idx]);
...
static void RenderFontGlyph(ref FontGlyph glyph)

或者你可以继续使用一个值参数,并根据达芬奇的答案,RenderFontGlyph返回你需要存储回数组中的修改后的值。

我当然不会说你很愚蠢,但理解引用类型和值类型的语义真的非常重要,特别是当你正在创建可变值类型时。(更糟糕的是,包含对可变引用类型的引用的可变值类型 - 在本例中为数组。您可以在不改变结构的情况下改变数组...如果你不小心,这一切都可能会变得非常混乱。

除非你有很好的理由来创建可变值类型,否则我强烈建议不要这样做 - 就像我也建议不要公开公共字段一样。你几乎肯定应该把FontGlyph建模作为一个类——对我来说,它不是一种自然的价值类型。如果您确实想将其建模为值类型,那么为什么不直接传入要呈现的代码点,并使该方法返回字形,而不是传入FontGlyph呢?

glyphs[0] = RenderGlyph(codePoint);

由于您声称按引用传递对您不起作用,因此这里有一个完整的示例来证明它确实有效。您应该将其与您的代码进行比较,看看您做错了什么:

using System;
struct FontGlyph 
{
public uint codepoint;
public byte[] bmp;
}
class Program
{
static void Main()
{
FontGlyph[] glyphs = new FontGlyph[100];
RenderFontGlyph(ref glyphs[0]);
Console.WriteLine(glyphs[0].bmp.Length); // 10
}
static void RenderFontGlyph(ref FontGlyph glyph)
{
glyph.bmp = new byte[10];
}
}

怎么样:

static void ConvertFont(Font fnt) {
...
if (fnt.IsSpaceCharacter) {
glyphs[idx].codepoint = 0x00FF;
glyphs[idx].bmp = null;
}
else {
glyphs[idx] = RenderFontGlyph(glyphs[idx]);
// glyphs[idx].bmp is NOT ok here - it is null!
}
...
}
static FontGlyph RenderFontGlyph(FontGlyph glyph) {
...
glyph.bmp = new byte[256];
// bmp is fine here, and can be populated as a normal array
...
return glyph;
} 

或者像这样使用refstatic void RenderFontGlyph(ref FontGlyph glyph)然后像这样称呼它:RenderFontGlyph(ref glyphs[idx])

相关内容

  • 没有找到相关文章

最新更新