【问题标题】:Why can't you use 'this' in member initializers? [duplicate]为什么不能在成员初始化器中使用“this”? [复制]
【发布时间】:2011-05-25 13:30:22
【问题描述】:

可能重复:
Cannot use ‘this’ in member initializer?

如果我尝试做这样的事情会出现错误的任何想法:

public class Bar
{
    public Bar(Foo foo)
    {
    }
}

public class Foo
{
    private Bar _bar = new Bar(this);
}

我收到一条错误消息:

"不能在成员初始化器中使用 'this'"

但以下工作:

public class Foo
{
    private Bar _bar;

    public Foo()
    {
        _bar = new Bar(this);
    }
}

有人知道这背后的原因吗?我的理解是这些会编译成相同的 IL,所以很好奇为什么一个被允许而另一个不被允许。

谢谢, 亚历克斯

【问题讨论】:

  • 我不知道为什么这个问题作为重复而被关闭,因为另一个问题的答案是关于为什么它没有被报告为错误被回答为“这是一个错误编译器”,而没有实际解释为什么不允许这样做。

标签: c#


【解决方案1】:

怀疑这是为了防止您在至少基类构造函数运行之前使用该对象,确保所有基类成员都已正确初始化。 (变量初始化器在基类构造函数之前执行,而构造函数主体在之后执行。)

当我下次靠近它时,我会检查带注释的规范是否有什么要说的......

编辑:C# 4 注释规范没有任何解释。只是(在 10.5.5.2 中):

实例字段的变量初始化器不能引用正在创建的实例。

【讨论】:

  • 很有趣,谢谢。从来没有意识到变量初始化器在基类ctor之前运行......
  • 你当然是对的。我们应该将它添加到下一个版本的注释规范中,这是一个很好的。
  • VS 建议将我的支持字段转换为Lazy
【解决方案2】:

字段初始化程序在基类构造函数之前运行,因此this 尚不存在。它仅在基本构造函数完成执行后才存在。

17.10.2 Instance variable initializers:

当实例构造函数没有 构造函数初始化器,或者它有一个 表单的构造函数初始化器 base(...),该构造函数隐式 执行指定的初始化 通过变量初始化器 在其类中声明的实例字段。 这对应于一个序列 执行的任务 进入后立即 构造函数和隐式之前 直接基类的调用 构造函数。变量 初始化程序在 它们出现的文本顺序 类声明。

【讨论】:

  • 它确实存在——只是还没有完全初始化。
【解决方案3】:

我相信这是因为字段在类初始化之前初始化,所以在运行以下代码时:

private Bar _bar = new Bar(this);

“this”没有实际可引用的值。

虽然把它放在构造函数中意味着有一个“Foo”的实例可以被“this”引用

【讨论】:

    【解决方案4】:

    成员初始化器在类构造函数之前运行。考虑到您可能在一个类中有许多成员初始化器。

    如果你在构造函数中使用 'this' -> 所有带有初始化器的成员都被初始化了。所以一切正常。

    如果您在成员初始化程序中使用“this”:其他成员(附加了初始化程序)可能尚未初始化 ->“this”尚未准备好。这就是为什么这里不允许使用 'this' 是不允许的。

    【讨论】:

      【解决方案5】:

      在 C# 中,没有任何逻辑旨在位于方法和属性的主体之外。

      字段初始化器是一个例外,但有一些限制。

      使用 this 关键字获取当前对象的引用是错误的,因为类字段声明不是逻辑而是类设计,而 this 是运行的一部分-时间语义。

      顺便说一句,这似乎是一个 C# 设计决定,因为事实上,字段初始化器在类构造期间运行,所以“声明类的当前实例”应该可以通过 this。但同样,this 在方法或属性主体范围之外是什么?

      正如 Jon Skeet 和其他人指出的那样,this 不可用,因为字段初始值设定项是在基本构造函数执行之后执行的。

      【讨论】:

      • 在方法或属性主体之外,它仍然是代码在其上下文中执行的对象。为成员初始化器允许这样做是完美的sense - 如果它尝试使用尚未被基类初始化的状态,那只会有问题。
      • 完全同意并感谢您的评论。这就是为什么我指出这是一个 C# 设计决定这一事实,但我提出这个问题是因为我发现在这个范围内有 this 关键字会让人感到困惑(它很容易成为一个整体的错误)。跨度>
      • ía离开。我认为从根本上说是有道理的 - 只是有一些警告。
      • @Jon Skeet。同意并感谢您提供的信息。事实上(就我而言),在我的代码中避免了字段初始化器。而且,例如,当我想设置只读字段时,我只初始化字段。我宁愿远离他们。为了设置私有字段,我使用属性设置器。
      猜你喜欢
      • 2011-01-02
      • 2010-09-18
      • 1970-01-01
      • 2013-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多