C#对象初始化器出了什么问题?

7

当我在 C# 中使用新对象初始化器初始化一个对象时,我无法使用类中的某个属性来执行进一步的操作,我不知道为什么。

我的示例代码:

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

在Person类中,x将等于0(默认值):

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

然而,person.Age确实等于29岁。我相信这是正常的,但我想知道原因。


你构造函数中的年龄应该是全小写还是像你的属性一样首字母大写?这可能有助于确定问题。 - Jeffrey Cameron
不,应该是年龄。抱歉打错了。 - dmce
6个回答

21

在构造函数“public Person()”完成运行后,属性会被设置为名称和年龄。

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

等同于

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

因此,在构造函数中,年龄尚未变为29。

(tempPerson是您在代码中看不到的唯一变量名称,它不会与以这种方式构造的其他Person实例发生冲突。使用tempPerson可以避免多线程问题;其使用确保在构造函数执行之后和初始化所有属性之后,新对象不会对任何其他线程可用。)


如果要在构造函数中操纵Age属性,则建议创建一个接受年龄作为参数的构造函数:

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

   // Now do something with Age
   int x = Age;
   // ...
}

这个回答中的第一句话不是正确的吗?“在构造函数'public Person()'运行完成后,属性Name和Age被设置。” - dmce
1
@Juan:你的“这是错误的”评论有些不友善。虽然这个答案在没有引用临时变量方面略有不准确,但是就所问的问题而言并没有错。请尽量礼貌一些,以防下次轮到你提问或回答。 - Jeff Yates
@Jeff:我们在这里回答问题,常常会伤害到他人的感情。这就是极客的生活,也是我们不从事销售工作的原因。 - yfeldblum

9
请注意,作为一个重要的技术细节,以下内容需要特别关注:
Person person = new Person { Name = "David", Age = "29" };

等同于:

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

但不等同于:
Person person = new Person();
person.Name = "David";
person.Age = "29";

为什么这很重要?我没有看到任何影响上的区别。 - Wim Coenen
+1 只是比我快一步...你是对的 wcoenen,你不会看到区别...直到另一个线程尝试读取 Person.Name - 但实际上没有设置,因为 <>0.Name 是... - John Rasch
是的,多线程是这个技术细节重要的原因。 - yfeldblum

6

您的代码行与以下代码完全相同:

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

这与以下内容完全相同:

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

正如您所看到的,在构造函数执行时,Age尚未设置。


当构造函数执行时,年龄仍然是29岁?真的吗? - Cameron MacFarland
抱歉 - 你知道我在说什么 ;-p - Marc Gravell
我唯一能看到的“错误”就是瞬态变量;对于所提出的问题,我认为这是一个不必要的细节。 - Marc Gravell

4

从技术上讲,这段代码:

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

与此代码完全相同:

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

这与其他人发布的略有不同:

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

如果您的应用程序使用多线程,这种差异非常重要。


3

看起来您正在尝试在对象的构造函数中访问Age。对象初始化程序的值要在构造函数执行后才能设置。

请尝试以下操作:

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

回应评论的编辑

如果你需要在构造函数中访问Age,那么你需要创建一个带有所需参数的显式构造函数,并使用它来代替对象初始化语法。例如:

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);

是的,这对我起作用了,但我想在构造函数中处理年龄。 - dmce

0

正如其他人所说,无参数构造函数首先被执行,因此你陷入了困境。

但我必须问一下,如果您为Age变量设置的是字段而不是自动属性吗?

public class Person
{
    private int _age;

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

如果足够的话,您可以使用_age代替x,或者如果您确实需要使用x

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

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

无论哪个更合适。


我使用了 Public int Age {get; set;} - 自动属性。 - dmce
dmce--确切地说。选择“手动”或“传统”的属性可以更轻松地解决这个问题。 - Jon Limjap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接