【问题标题】:Initially assigned variables最初分配的变量
【发布时间】:2013-04-08 01:57:27
【问题描述】:

最初分配了以下两类变量:

  • 类实例的实例变量。

  • 最初分配的结构变量的实例变量。

现在最初分配的结构变量是什么意思?

我们不是在谈论局部变量,对吧?所以我们说的是函数成员定义中使用的字段变量(在这两个类别中)?

澄清这一点将不胜感激。提前致谢!

【问题讨论】:

  • 结构不能为空,因此它们必须有一个值——int、bool、枚举也属于该类别。

标签: c# variables variable-assignment


【解决方案1】:

你的问题不是很清楚。但是,始终将类或结构的 field(实例或静态)视为已分配是正确的。它将具有类型的默认值,对于引用类型和可空类型,它是 null,对于其他值类型,它是“零”或类似于零的东西。

相比之下,局部变量,即在方法(或构造函数,或访问器等)中声明的变量,必须在使用前显式赋值。

在示例中:

class Example
{
    int field;

    void Method()
    {
        int local;
        ...
        ...
    }
}

field 被认为是自动赋值的,并将具有初始值 0,而变量 local 未赋值,必须先赋值(稍后以相同的方法)才能使用(甚至稍后在同样的方法)。

不过,未分配的局部变量可以作为方法的 out 参数传递。

编辑:(在有用的 cmets 之后)

我上面的回答对类的(静态和非静态)字段和结构的静态字段给出了非常精确的描述。但是,正如 cmets 指出的那样,在结构的实例字段的情况下,缺少一些东西。

当结构实例的所有实例字段都被完全分配时,它被完全分配。给定以下(可变的!!)结构:

struct SomeStruct
{
    public int AlphaField;
    public int BetaField;
}

那么以下是合法的:

void M()
{
    SomeStruct localSS;
    // localSS and its fields are not assigned, and can't be read yet

    localSS.AlphaField = 7;           // legal
    int useA = localSS.AlphaField;    // legal, AlphaField is assigned
    // localSS and its remaining field BetaField are not assigned

    localSS.BetaField = 13;
    string useB = localSS.ToString(); // legal, localSS variable is now fully assigned
}

即使上面的例子看起来很疯狂(因为大多数人不鼓励可变结构),它仍然完全等同于在结构的用户定义实例构造函数中发生的事情。 C# 规范使用这句话:结构的实例构造函数的this 变量的行为与结构类型的out 参数完全相同——特别是,这意味着必须明确地分配变量实例构造函数的每一个执行路径。

请注意,结构的实例构造函数分配所有字段的一种方法是使用 : this(...) 构造函数链接语法链接另一个实例构造函数。

还要注意结构的实例构造函数必须带参数。表达式new SomeStruct()(参数列表为空)等价于default(SomeStruct),并计算为SomeStruct 的明确分配实例,其中所有字段都有其默认值。

【讨论】:

  • 但是结构的字段最初没有被分配。只有类的字段是。
  • 但是结构的字段最初没有被分配。只有类的字段是。
  • @user2247389 好吧,从某种意义上说你是对的。在示例struct MyStruct { int field; } 中,我们没有给出实例构造函数。但仍然允许说var ms = new MyStruct();。在这种情况下,ms 上的field 将具有值0。但是,如果您确实为您的结构编写了实例构造函数,则必须在控制离开构造函数之前分配所有实例字段。并且在实例构造函数中的字段在被分配之前是不允许使用的。所以我的回答错过了这个细节。分配所有字段的一种方法是 chain 另一个构造函数。
  • @JeppeStigNielsen S s; /* uninitialized struct local variable */ int x = s.F; /* error, field might not be initialized */ s.F = 42; int y = s.F; /* valid now */ 怎么样?
  • @svick 这是一个很好的例子。我会看看我是否可以更新我的答案。
【解决方案2】:

初始赋值的变量有以下两类:(1)类实例的实例变量和(2)初始赋值的struct变量的实例变量。 “最初分配的结构变量”是什么意思?

它表示一个结构类型的初始分配变量

跟随。

class C 
{
    public int i;
}
...
C c = new C();
Console.WriteLine(c.i);

c.i是一个类的实例变量,所以初始赋值

struct S 
{
    public int j;
}
class D 
{
    public S t;
}
...
D d = new D();
Console.WriteLine(d.t.j);

d.t是一个类的实例变量,所以是初始赋值的。 d.t.j 是结构体S 的实例变量,S 类型的变量d.t 是初始赋值的,因此d.t.j 也是初始赋值的。

也就是说,如果保存结构的值的变量是本身最初分配的,则结构的字段是最初分配的。

相比之下:

void M()
{
    int q;
    Console.WriteLine(q); // Error
    S u;
    Console.WriteLine(u.j); // Error

qu 最初都没有分配;它们不是任何类的字段。由于 u 最初没有被分配,u.j 也不是。

现在有意义吗?

【讨论】:

  • 从此完美!非常感谢埃里克!我问了我的导师两次这个问题,他甚至都没有说得通。
【解决方案3】:

类(在 C# 中)是引用类型的定义。这意味着该类的任何成员都存储为引用。

结构(在 C# 中)是值类型的定义。此类的任何成员都存储为值,而不是引用。

引用类型可以取消分配,因为在使用它们之前不需要分配。使用未分配的类实例成员会导致运行时错误。

值类型需要一个值来存储,否则它们将无法确定它们的内存空间。使用未分配的结构成员会导致编译时错误。

【讨论】:

  • 您是说如果我有一个包含五个ints 作为成员的类,那么每个int 都作为单独的引用存储?或者具有string 成员的结构不会存储string 作为参考?这当然不对。引用和值类型不是关于类型成员的存储,而是关于类型本身的实例。
  • 不,这根本不是我要说的。我是说类的每个实例都存储为参考。 int 是值类型,string 是在大多数情况下被视为值类型的引用类型。这就是为什么你不需要说string s = new String("Hello")。但显然 Eric Lippert 的答案要好 9001 倍,所以请投反对票,而不是解释答案有什么问题或编辑它以使其“正确”。
  • 也许这就是你的意思,但这不是你所说的(至少不是我理解的那样)。您的答案是关于一个类的成员,而不是它的实例。 (我很困惑,我确实解释了我认为你的回答有什么问题。)
  • 问题是“初始分配的结构变量是什么意思?”你回答了这个问题吗?
  • @EricLippert 我以为我做到了。我不确定我的回答有什么不清楚的地方。我认为以多种方式解释某事是有价值的,我想确保我的口头解释是完整的。在这种情况下,您的代码解释更完整,但我宁愿修复我的答案而不是删除它。被认为是错误的/不完整的比投反对票所传达的失分更让我困扰:)
猜你喜欢
  • 1970-01-01
  • 2021-07-12
  • 2015-12-23
  • 2019-04-08
  • 2017-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多