C#Object Initialiser – 对新实例的引用

我可以以某种方式获得对使用对象初始化器创建的实例的引用

var x = new TestClass { Id = 1, SomeProperty = SomeMethod(this) } 

“this”应该指向我正在创建的新TestClass实例。 但它显然是指代码所在的类的实例。

我不是在问这是否是一个很好的方法。 我知道我可以这样做:

 var x = new TestClass {Id= x}; x.SomeProperty = SomeMethod(this); 

我有一个复杂的场景,在对象初始化器中引用新实例会使生活更轻松。

这有可能吗?

没有办法绕过它,C#规范明确地说“对象或集合初始化程序不可能引用正在初始化的对象实例。”

至于为什么这是不可能的,我怀疑没有很好的方法来实现它。 我们想要一些相当于的语法糖

 var temp = new TestClass(); temp.Id = 1; temp.SomeProperty = SomeMethod(temp); x = temp; 

我们只需要一个关键字来引用初始化程序中的temp ,但没有一个容易获得。 我们不能使用this因为它已经意味着初始化器之外的东西。 SomeProperty = this.SomeMethod(this)是否等同于temp.SomeProperty = this.SomeMethod(temp)temp.SomeProperty = temp.SomeMethod(temp) ? 第二个是一致的,但如果我们需要第一个会发生什么?

我们可以尝试使用x ,但是如果新对象立即分配给变量,我们只能选择一个名称。 但是,我们现在无法在初始化器中引用x的旧值,相当于temp.SomeProperty = SomeMethod(x)

我们可以重用属性setter中的value关键字。 这听起来不错,因为如果您认为属性getter是set_SomeProperty(value)方法的语法糖,则value已经代表缺少的参数。 使用它来引用对象初始化器中缺少的变量看起来很有希望。 但是,我们可以在属性设置器中创建此对象,在这种情况下, value已经被使用,我们需要能够执行temp.SomeProperty = SomeMethod(value)

看起来我们必须为此目的创建一个新的关键字,也许是newthis 。 但是,这是对语言的重大更改,因为任何具有名为newthis的变量的代码都不再起作用。 Microsoft通常需要一个非常好的理由来引入重大更改,因此最好禁止访问正在初始化的对象。

不,你不能使用对象初始化器来分配你正在其他地方创建的对象 – 这会破坏对象初始化器的整个点。 在对象初始化程序完成之后才会分配x变量。 您需要分配对象,然后在单独的语句中使用它。

 var x = new TestClass { Id = 1 }; x.SomeProperty = SomeMethod(x); 
 var x = new TestClass { Id = 1, SomeProperty = SomeMethod(this) } 

在评估和执行此初始化的右侧部分之前,对代码尚未提供对新对象的引用。 这样做是为了安全起见,否则你可能会用代码创建一些死锁或无限循环。

暴露或使用尚未完全构建的物体通常是一个非常糟糕的主意。 考虑以下:

 class Connection { internal string connectionString; public Connection(ConnectionPool pool, string connectionString) { this.pool = pool; //this.connectionString = connectionString; // I moved it because I could. this.pool.Register(this); this.connectionString = connectionString; this.Init(); } private void Init() { //blah } } class ConnectionPool { public void Register(Connection c) { if ( this.connStrings.Contains( c.connectionString ) ) // BOOM } } 

这是一个非常人为的例子。 事情可能比这更糟糕。 以下是关于这个问题的一个非常有趣的链接: 部分构造的对象