views:

310

answers:

6

When i initialize an object using the new object initializers in C# I cannot use one of the properties within the class to perform a further action and I do not know why.

My example code:

Person person = new Person { Name = "David", Age = "29" };

Within the Person Class, x will equal 0 (default):

public Person()
{
  int x = Age; // x remains 0 - edit age should be Age. This was a typo
}

However person.Age does equal 29. I am sure this is normal, but I would like to understand why.

+19  A: 

The properties get set for Name and Age after the constructor 'public Person()' has finished running.

Person person = new Person { Name = "David", Age = "29" };

is equivalent to

Person tempPerson = new Person()
tempPerson.Name = "David";
tempPerson.Age = "29";
Person person = tempPerson;

So, in the constructor Age won't have become 29 yet.

(tempPerson is a unique variable name you don't see in your code that won't clash with other Person instances constructed in this way. tempPerson is necessary to avoid multi-threading issues; its use ensures that the new object doesn't become available to any other thread until after the constructor has been executed and after all of the properties have been initialized.)


If you want to be able to manipulate the Age property in the constructor, then I suggest you create a constructor that takes the age as an argument:

public Person(string name, int age)
{
   Name = name;
   Age = age;

   // Now do something with Age
   int x = Age;
   // ...
}
Scott Langham
this is wrong, see newer answers
Juan Manuel
Isnt the first statement in this answer correct though"The properties get set for Name and Age after the constructor 'public Person()' has finished running."
dmce
@Juan: You're being somewhat unkind with your comments of "this is wrong". While this answer is slightly inaccurate with regards to not referencing the temporary variable, it is not wrong with regards to the question being asked. Try to be more polite, lest it be your question or answer next time.
Jeff Yates
Thanks for the feedback, answer updated appropriately.
Scott Langham
@Jeff: We answer questions here, often at the expense of unsoothed feelings. Such is a geek's life, and the reason why we're not in sales.
Justice
+1  A: 

It looks like you're trying to access Age in the object's constructor. The object initializer values won't be set until after the constructor has executed.

Try this:

Person person = new Person { Name = "David", Age = 29 };
int x = person.Age;


EDIT in response to comment

If you need access to Age in the constructor itself then you'll need to create an explicit constructor with the required parameters, and use that instead of the object initializer syntax. For example:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;

        int x = Age;  // will be 29 in this example
    }
}

Person person = new Person("David", 29);
LukeH
unexplained downvotes are a plague
Neil N
voting up just to p.o. whoever downvoted
Neil N
Yes this worked for me but i want to do something with Age when i was still in the constructor
dmce
+5  A: 

Your line of code is identical to:

Person person = new Person() { Name = "David", Age = "29" };

which is identical to:

Person person = new Person();
person.Name = "David";
person.Age = "29";

As you can see; when the constructor executes, Age is not yet set.

Marc Gravell
"When the constructor executes, Age is still 29"? Really?
Cameron MacFarland
Ooops - you know what I mean ;-p
Marc Gravell
this is wrong, see newer answers
Juan Manuel
The only thing "wrong" I can see is the transient variable; for the question asked, I felt this was an unnecessary detail.
Marc Gravell
+8  A: 

Note, as an important technical detail, that:

Person person = new Person { Name = "David", Age = "29" };

is equivalent to:

Person <>0 = new Person(); // a local variable which is not visible within C#
<>0.Name = "David";
<>0.Age = "29";
Person person = <>0;

but is not equivalent to:

Person person = new Person();
person.Name = "David";
person.Age = "29";
Justice
Why is this important? I don't see any difference in the effect.
Wim Coenen
+1 for just beating me to it... you are correct wcoenen, you wouldn't see the difference... until a different thread tries to read Person.Name - but isn't actually set because <>0.Name is...
John Rasch
Yep, multithreading is the reason this technical detail is important.
Justice
+3  A: 

Technically, this code:

Person person = new Person { Name = "David", Age = 29 };

is identical to this code:

Person tmpPerson = new Person();
tmpPerson.Name = "David";
tmpPerson.Age = 29;
Person person = tmpPerson;

which is slightly different than what others have posted:

Person person = new Person();
person.Name = "David";
person.Age = 29;

This difference is crucial if your application is using multi-threading.

John Rasch
A: 

Well, as others said, the parameterless constructor got executed first, hence your quandary.

I do have to ask however, if you've set a field instead of an automatic property for your Age variable?

public class Person
{
    private int _age;

    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }
 }

You could use _age instead of x if that's enough, or if you really need to use x:

public class Person
{
    private int _age;
    private int x;

    public int Age
    {
        get { return _age; }
        set 
        { 
            _age = value;
            x = _age;
        }
    }
 }

Whichever is more appropriate.

Jon Limjap
I used Public int Age {get; set;} - automatic properties
dmce
dmce -- precisely. "Manual" or "traditional" properties would make it easier for you to get around this problem.
Jon Limjap