以下C#结构用于表示颜色分量和32位颜色值本身的并集.问题是编译器给出了错误:
错误CS0171在将控制权返回给调用者之前,必须完全分配字段'Color.ARGB'
是否可以在不初始化数据两次的情况下消除此错误?这是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);
}
Run Code Online (Sandbox Code Playgroud)
是否可以在不初始化数据两次的情况下消除此错误?
是的,不是.
这里的假设是成员尚未"初始化两次".当您从内存分配器获取新结构时 - 无论是从堆还是堆栈 - 它将自动归零.
正如Naidu的回答所说,调用默认构造函数向编译器指示"运行时必须将此事件归零(如果它还没有);我希望断言对于未被构造函数写入的对象的任何部分,我很好它的默认状态".
实际上,通常抖动已经初始化为零,因此通常不会进行额外的初始化.但是,内存分配器自动将状态初始化为零的行为依赖于运行时实现.同样是实现相关的行为,如果抖动是否能优化掉零出的行为也知道,每场被初始化.
这里有微妙之处.假设例如内存未被清零,因为抖动推断出构造函数会写入每个字段.现在假设在构造函数的中途抛出线程中止异常.是否有可能另一个线程观察对象的未归零,未写入状态?如果事实上有可能会发生什么样的地狱般的行为呢?给出一些想法.
这是C#的预期行为吗?
是.
编译器不知道你正在创建一个类型不安全的联合.它不知道这些属性的含义.
如果我初始化两次,JIT会检测到双初始化并且只执行第二次初始化吗?
许多不同的平台上有许多不同的紧张情绪.如果您想要回答您的问题,请使用所有可能的配置尝试所有问题并查看会发生什么.
无论如何,你可能会担心没什么重要的.将零写入内存非常快.执行不必要的零写操作可能不是程序中的瓶颈.
查看下面的微软链接:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0843
它说,
要从构造函数为自动实现的属性赋值,必须首先调用默认构造函数来创建对象。
进行以下更改将解决您的问题。调用默认构造函数。
public Color(byte r, byte g, byte b, byte a = 0xff):this()
{
A = a;
R = r;
G = g;
B = b;
}
Run Code Online (Sandbox Code Playgroud)