以下 C# 结构用于表示颜色分量和 32 位颜色值本身的并集。问题是编译器报错:
Error CS0171 Field 'Color.ARGB' must be fully assigned before control is returned to the caller
是否可以在不初始化数据两次的情况下摆脱这个错误?这是 C# 的预期行为吗?如果我初始化两次,JIT 会检测到双重初始化并只执行第二次吗?
[StructLayout(LayoutKind.Explicit)]
public struct Color
{
public Color(byte r, byte g, byte b, byte a = 0xff)
{
ARGB = 0; // The init I shouldn't have to do
A = a;
R = r;
G = g;
B = b;
}
[FieldOffset(0)]
public byte B;
[FieldOffset(1)]
public byte G;
[FieldOffset(2)]
public byte R;
[FieldOffset(3)]
public byte A;
[FieldOffset(0)]
public uint ARGB;
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
}
最佳答案
Is it possible to get rid of this error without initialize the data twice?
是也不是。
这里的假设是成员还没有“初始化两次”。当您从内存分配器(无论是从堆还是堆栈)获取新结构时,它将自动清零。
正如 Naidu 的回答指出的那样,调用默认构造函数向编译器表明“运行时必须将这个东西清零,如果它还没有;我想断言我对构造函数未写入的对象的任何部分都很好处于默认状态“。
在实践中,抖动通常已经初始化为零,因此通常不会进行额外的初始化。但是,内存分配器自动将状态初始化为零的行为取决于运行时实现。类似地,如果抖动知道每个字段都已初始化,那么抖动是否可以优化零输出行为是一种依赖于实现的行为。
这里有一些微妙之处。例如,假设内存没有清零,因为抖动推断出您的构造函数写入了每个字段。 现在假设在构造函数中途抛出一个线程中止异常。另一个线程是否有可能观察到对象的未清零、非您编写的状态?如果这是可能的,那会造成什么 hell 般的行为?考虑一下。
Is this expected behavior of C#?
是的。
编译器根本不知道您正在创建一个类型不安全的联合体。它不知道这些属性的含义。
If I init twice, will the JIT detect the dual init and only do the second one?
在许多不同的平台上有许多不同的抖动。如果您想要问题的答案,请尝试使用所有可能的配置对它们进行尝试,看看会发生什么。
无论如何,您可能不会担心任何重要的事情。 将零写入内存非常快。进行不必要的零写入可能不是您程序的瓶颈。
关于c# - C# 中的显式结构需要双重初始化值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54700723/