2017-05-15 43 views
23

我有下面的代码类:为什么`this`在C#6.0自动属性初始化中不可用?

public class Foo 
{ 
    public Nested Bar { get; } = new Nested(this); 

    public class Nested 
    { 
     public Nested(Foo foo) 
     { 
      foo.DoSomething(); 
     } 
    } 

    private void DoSomething() 
    { 

    } 
} 

不过,我得到这个编译错误:

Keyword 'this' is not available in the current context

我可以简单地通过不使用自动属性初始化程序修复它,并明确将其移动到构造函数代替:

public Nested Bar { get; } 

public Foo() 
{ 
    this.Bar = new Nested(this); 
} 

为什么会这样?自动属性初始值设定项实际上是否转换为IL中的构造函数代码?

+3

。您不能在字段初始值设定项中引用它,因为字段初始值设定项在构造函数之前运行,所以没有构建的对象尚未使用。 – Evk

+0

@Evk是否这样,当构造函数运行时,对象也是“尚未构造”? –

+0

一个有趣的问题Roland Pihlakas!该对象必须已经存在,正在准备访问的内存。否则,该物业不会在那里。但没有其他东西被初始化。人们可以在构造函数中执行初始化步骤的错误顺序,但对程序员来说更明显。 – Droidum

回答

42

简单:你不能在初始化使用this。这样做是为了防止一个完全的对象逃跑 - Nested(this)可以做任何事情你的对象,从而导致非常混乱,很难理解错误。请记住,初始化之前执行您添加的任何构造。现场初始化同样的事情也会失败,在完全相同的方式:

private Nested _field = new Nested(this); 

从本质上讲,初始化旨在执行简单初始化 - 固定的98%的问题。任何涉及this是更复杂,你需要编写自己的构造 - 因为自动初始化财产被翻译成支持字段与初始引咎任何时间问题:)

+0

TIL!如果您不介意,我有点好奇:是否有关于初始化程序中的内容的详细信息/文档?为什么不直接把它放在构造函数中(在显式构造函数代码之前)? –

+4

@DatVM本质上是IL在IL级别发生的事情;我非常故意地说“你添加的任何构造函数” - 所以:*如果你添加了一个构造函数,它将没有时间去做任何事情。还有初始化顺序的问题:哪些初始化器已经运行了?如果你没有构造函数的显式时间,它会变得非常棘手。语言作者不喜欢添加细微复杂因素的东西,因此:这个用法被迫使用构造函数。 –

+1

@datvm在构造函数中执行它不会阻止像'private int a = this.b; private int b = this.a;' - 虽然可能会捕获这样的特定不可解决的情况,但是在批量中禁止使用'this'要简单得多。 – IllusiveBrian

17

Why is it so? Isn't Auto-Property Initializer actually translated into constructor code in IL?

由于相同的原因,自动实现的属性初始值设定项的规则与域初始值设定项的规则相同。需要注意的是属性初始化执行之前基类的机构,就像字段初始化 - 所以你仍处于“有点未初始化”对象的上下文;比在构造函数体中更重要。

所以,你应该想象的属性被转换成这样:

private readonly Nested bar = new Nested(this); // Invalid 

public Nested Bar 
{ 
    get { return bar; } 
} 

总之,这种限制是避免给自己带来麻烦阻止你。如果在初始化属性时需要参考this,则只需在构造函数中手动执行该操作即可,如第二个示例所示。 (这是我的经验比较少见的。)

+0

是不是它被转换成一个'readonly'场?对于错误发生的原因你并不完全重要。 – TheLethalCoder

+0

@TheLethalCoder:是的,将编辑。 –