与很少使用的值类型初始化混淆

本文关键字:类型 初始化 | 更新日期: 2023-09-27 18:00:04

以下代码是非法的:

public struct MyStruct
{
    public MyStruct(int a, int b)
    {
        this.a = a;
        this.b = b;
    }
    public int a;
    public int b;
}
//now I want to cache for whatever reason the default value of MyStruct
MyStruct defaultValue;
...
if (foo != defaultValue) //use of unassigned variable...

事情应该做的方式显然是:

MyStruct defaultValue = default(MyStruct) //or new MyStruct();
...
if (foo != defaultValue) //compiler is happy

但以下也是允许的(我不知道这一点,偶然发现了它):

MyStruct defaultValue;
defaultValue.a = 0;
defaultValue.b = 0;
...
if (foo != defaultValue) //legal

我猜编译器会验证struct的所有字段都已初始化,因此允许编译此代码。尽管如此,我还是发现它与其他语言的工作方式相混淆。毕竟,您基本上是在用C#的方式来看待事物,使用一个未分配的变量。

如果你考虑以下代码,事情会变得更加混乱:

public struct MyStruct
{
    public MyStruct(int a, int b)
    {
        this.a = a;
        this.b = b;
        this.c = (a + b).ToString();
    }
    public int a;
    public int b;
    internal string c;
}

以下代码是非法的,因为在这种情况下,我们没有分配所有可见字段:

MyStruct defaultValue;
defaultValue.a = 0;
defaultValue.b = 0;
...
if (foo != defaultValue) //use of unassigned variable...

Visible是这里的关键词,因为如果在引用的程序集中定义MyStruct,那么c就不可见,编译器不会抱怨,并且以前的代码将完全有效。再次困惑。

请somebdoy解释一下为什么允许以这种方式在C#中初始化struct?为什么不完全禁止它,这样在处理语言中的任何类型的值时都会有更统一的体验?

编辑1:我在上一个例子中犯了一个错误。只有当不可见字段是引用类型时,编译器才会感到高兴。更令人困惑。最后一种情况是编译器中已知的错误,还是有合理的理由让它以这种方式工作?

将上一个示例更改为有效案例。

EDIT 2:我对值类型初始化的工作原理仍然有点困惑。例如,为什么不允许以下内容:

struct MyStruct
{ 
    public int A { get; set; } //Auto-implemented property
    public int B { get; set; } //Auto-implemented property
}
MyStruct defaultValue;
defaultValue.A = 0;  //use of unassigned variable...
defaultValue.B = 0;

在我看来,毫无疑问,所有字段MyStruct都已初始化。如果属性不是自动实现的,我可以理解为什么不允许这样做,因为可以说setter没有保证所有字段都已设置。但在自动实现的属性中,编译器100%确定地知道,如果属性是(在编译器为您生成所有代码之后),则字段将被设置。

最后,一个显然没有实际用途的小理论案例:

struct MyUselessStruct
{
}
MyUselessStruct defaultValue;
Console.WriteLine(defaultValue.ToString()); //hehe did I get away with using an unassigned variable?

那么为什么不允许这样做:

Object object;
if (object == null) .... //use of unassigned variable

我发现这两种情况在概念上相似,我希望它们在C#中以相同的方式工作。我仍然不明白为什么可以初始化值类型变量的这种看似无用的区分,以及它的实际用途是什么(除了我在问题的第一部分解释的不一致之外)

与很少使用的值类型初始化混淆

规范明确允许这样做;12.3在ECMA334v4 中

  • 如果结构类型变量的每个实例变量都被认为是明确赋值的,那么它就被认为是绝对赋值的

然而,可变结构是邪恶。所以我强烈建议你不要这样做。

使字段私有为只读,通过自定义构造函数设置它们,并通过get-only属性访问它们:

public struct MyStruct
{
    public MyStruct(int a, int b)
    {
        this.a = a;
        this.b = b;
    }
    public int A { get { return a; } }
    public int B { get { return b; } }
    private readonly int a, b;
    internal int C { get { return a + b; } }
}