What am I doing wrong with C# object initializers?
Asked Answered
C

6

7

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.

Clements answered 17/2, 2009 at 22:3 Comment(2)
Is the age in your constructor supposed to be all lowercase or titlecase like your property is? That could go a way toward determining the problemApparatus
no it should be Age. Sorry typoClements
K
21

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;
   // ...
}
Kaspar answered 17/2, 2009 at 22:5 Comment(3)
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."Clements
@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.Improvised
@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.Geoponics
G
9

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";
Geoponics answered 17/2, 2009 at 22:14 Comment(3)
Why is this important? I don't see any difference in the effect.Yacht
+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...Georama
Yep, multithreading is the reason this technical detail is important.Geoponics
L
6

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.

Lashing answered 17/2, 2009 at 22:6 Comment(3)
"When the constructor executes, Age is still 29"? Really?Analyzer
Ooops - you know what I mean ;-pLashing
The only thing "wrong" I can see is the transient variable; for the question asked, I felt this was an unnecessary detail.Lashing
G
4

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.

Georama answered 17/2, 2009 at 22:16 Comment(0)
D
3

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);
Dropout answered 17/2, 2009 at 22:5 Comment(1)
Yes this worked for me but i want to do something with Age when i was still in the constructorClements
H
0

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.

Hacienda answered 17/2, 2009 at 22:39 Comment(2)
I used Public int Age {get; set;} - automatic propertiesClements
dmce -- precisely. "Manual" or "traditional" properties would make it easier for you to get around this problem.Hacienda

© 2022 - 2024 — McMap. All rights reserved.