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

标签 c# value-type

以下代码是非法的:

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...

可见 是这里的关键词,因为如果要在引用的程序集中定义 MyStruct,则 c 不可见 并且编译器不会报错,之前的代码将完全有效。又糊涂了。

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

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

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

编辑 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# 中的工作方式相同。我仍然不明白为什么这种看似无用的值类型变量初始化方式的区别以及它的实际用途是什么(除了我在问题的第一部分中解释的不一致之外)

最佳答案

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

  • A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.

但是,可变结构是邪恶的。所以我强烈建议您不要这样做。

将字段设为私有(private)只读,通过自定义构造函数设置它们,并通过 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; } }
}

关于c# - 与很少使用的值类型初始化混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6437454/

相关文章:

c# - Entity Framework 4 : Code First - Creating db in another schema? MapSingleType?

c# - ValueTypes 如何从 Object (ReferenceType) 派生并仍然是 ValueTypes?

swift - 就地改变值类型关联值

java - 我们可以向 Java 添加结构吗?

c# - 在 ListView 中更改选择突出显示颜色

c# - Linq to SQL 用定界符追加多条记录

c# - 如何从 RichTextBox 控件的撤消堆栈中删除操作?

c# - 通过反射获取可选 Guid 的默认值?

c# - 正确使用 MemoryCache 和泛型?

c# - 等待一个线程在循环中存活是好习惯吗?