C# Object Initialiser - Reference to the new instance
Asked Answered
C

4

6

Can I somehow get a reference to the instance I am creating using object initialiser

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

"this" should point to the new TestClass instance I'm creating. But it obviously refers the the instance of the class in which this code resides.

I'm not asking if this is a good way to do this. I'm aware that I can do this like this:

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

I have a complicated scenario, in which a reference to the new instance in the object initialiser would make life easier.

Is this possible in any way?

Comeau answered 25/8, 2010 at 9:51 Comment(0)
Y
9

There's no way around it, the C# specification explicitly says that "It is not possible for an object or collection initializer to refer to the object instance being initialized."

As for why it's impossible, I suspect that there's just no nice way to implement it. We want some syntactic sugar equivalent to

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

We just need a keyword to refer to temp within the initializer, but none is easily available. We can't use this because it already means something outside the initializer. Should SomeProperty = this.SomeMethod(this) be equivalent to temp.SomeProperty = this.SomeMethod(temp) or temp.SomeProperty = temp.SomeMethod(temp)? The second is consistent, but then what happens if we need the first?

We could try to use x, though we can only pick a name if the new object is immediately assigned to a variable. However, we now can't refer to the old value of x inside the initializer, doing the equivalent of temp.SomeProperty = SomeMethod(x).

We could reuse the value keyword from property setters. This sounds good since value already stands in for the missing parameter if you consider a property getter to be syntactic sugar for a set_SomeProperty(value) method. Using it to also refer to the missing variable in the object initializer looks promising. However, we could be creating this object inside a property setter, in which case value is already being used, and we need to be able to do temp.SomeProperty = SomeMethod(value).

It looks like we'll have to create a new keyword just for this purpose, maybe newthis. However, this is a breaking change to the language because any code that has a variable called newthis doesn't work any more. Microsoft generally needs a really good reason to introduce breaking changes, so it's better to forbid access to the object being initialized.

Yarndyed answered 25/8, 2010 at 10:37 Comment(2)
It is interesting that C# does not support this because VB does. Something like new MyObject() with {.Property1 = "x", .Property2=.Property1+"y"} does work. Usually the language functionality is very similar but it appears in this case it is not. I have a rather complex LINQ query that I just can't seem to convert to C# due to this limitation.Nickens
Could this be implemented without causing breaking changes by reusing the keyword "private"?Rosenstein
S
1

No, you can't use the object initializer to assign the object you're creating somewhere else - that defeats the whole point of the object initializer. The x variable doesn't get assigned until after the object initializer is completed. You'll need to assign the object, then use it in a separate statement.

var x = new TestClass {
    Id = 1
};
x.SomeProperty = SomeMethod(x);
Supervise answered 25/8, 2010 at 9:53 Comment(3)
{ x = y } is syntax sugar. it happens outside of constructor.Whither
Yes, but the x variable isn't assigned until after the initializer is completedSupervise
@thecoop: Please note that I am not using the 'x' variable. I am referring to an (apparently non-existing) keyword.Comeau
E
0

Exposing or using an object that hasn't been fully constructed is usually a very bad idea. Consider the following:

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

This is an extremely contrived example. Things can get a whole lot worse than this. The following was quite an interesting link regarding this issue: Partially Constructed Objects

Embezzle answered 25/8, 2010 at 12:8 Comment(1)
As Andrey pointed out: " { x = y } is syntax sugar. it happens outside of constructor. "Comeau
C
-2
var x = new TestClass
           {
                 Id = 1,
                 SomeProperty = SomeMethod(this)
           }

Before the right part of this initialization is evaluated and executed, the reference to the new object is not yet made available to the code. That is done for security purposes, otherwise you could create some deadlock or endless loop with you code.

Coroneted answered 25/8, 2010 at 9:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.