【问题标题】:Can I use Object Initialization Syntax to assign values to properties before the constructor runs?我可以在构造函数运行之前使用对象初始化语法为属性赋值吗?
【发布时间】:2012-06-20 18:07:55
【问题描述】:

我正在使用 System.Xml.Serialization 将对象序列化为 XML,这需要我有无参数的构造函数。

因此,我尝试使用对象初始化语法将值分配给某些属性,然后在将对象序列化为 XML 之前使用构造函数逻辑根据需要格式化这些值。

我的问题是构造函数在属性被赋值之前运行。下面是一个简化的例子:

class Program
{
    static void Main(string[] args)
    {
        Foo myFoo = new Foo() { HelloWorld = "Beer", HelloWorldAgain = "More beer" };

        Console.WriteLine(myFoo.HelloWorld);
        Console.WriteLine(myFoo.HelloWorldAgain);

        Console.ReadLine();
    }
}

public class Foo : Bar
{
    public string HelloWorld { get; set; }

    public Foo()
    {
        Console.WriteLine("Foo Was Initialized");
        Console.WriteLine(HelloWorld);
    }
}

public abstract class Bar
{
    public string HelloWorldAgain { get; set; }

    public Bar()
    {
        Console.WriteLine("Bar was initialized");
        Console.WriteLine(HelloWorldAgain);
    }
}

这会产生以下输出:

如您所见,构造函数逻辑运行,然后属性被赋值。我需要这个以相反的方式工作。

这可能吗?

【问题讨论】:

  • 您打算使用哪种预序列化格式?
  • 我传入一个 ID,然后对数据库运行查询以提取各种信息,并将这些信息分配给自动属性,我认为这样做会更整洁在构造函数中

标签: c# constructor initialization


【解决方案1】:

序列化要求你有一个无参数的构造函数,但不限制你使用那个构造函数。

保留无参数构造函数用于反序列化,但添加另一个构造函数,当您需要在代码中实例化类时,该构造函数接受您的值并执行所需的初始化。

对象初始化语法只是构造后设置属性的简写。

【讨论】:

    【解决方案2】:

    没有。对象初始化语法只是一个捷径。当你写:

    Foo foo = new Foo { HelloWorld  = "Beer" };
    

    编译器只是将其重写为与您编写时非常接近的内容:

    Foo foo = new Foo();
    foo.HelloWorld  = "Beer";
    

    如果您的对象需要参数才能存在,您应该将它们作为参数放入构造函数中。

    【讨论】:

    • XML 序列化确实需要一个无参数的公共构造函数,但您可以按照 API 使用者的建议使用其他构造函数重载。
    • @Reed,学究式,it's not exactly the same 就像你写的那样。
    • @KirkWoll 非常正确 - 我编辑了语言 - 它只是在概念上类似于心智模型,但是是的,它并不完全相同 ;)
    【解决方案3】:

    不,这是不可能的,因为为了能够初始化对象的属性,对象已经存在。它的存在是由 ctor 在所有其他东西之前运行 来保证的。

    如果我们在谈论“不运行默认构造函数”,就像一个概念性问题。 您可以通过使用static 属性来做到这一点。在这种情况下 Foo() 将不会被调用。但这自然不在当前的问题主题范围内。

    【讨论】:

      【解决方案4】:

      可以说,语法具有欺骗性。这里发生了什么?

      var myFoo = new Foo();
      myFoo.HelloWorld = "Beer";
      myFoo.HelloWorldAgain = "MoreBeer";
      

      恐怕就是这样。 在构造函数运行之前根本不可能初始化属性。构造函数是在为对象分配内存并将默认值分配给字段之后“发生”的第一件事。

      顺便说一句,您不需要使用对象初始化语法的括号。这也一样好(但更具欺骗性):

      var myFoo = new Foo { HelloWorld = "Beer", HelloWorldAgain = "MoreBeer" };
      

      看看你的问题,看起来你正在尝试做的事情(在序列化之前修改属性)不属于构造函数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-13
        • 2018-05-02
        • 1970-01-01
        • 2012-07-22
        • 1970-01-01
        • 1970-01-01
        • 2011-09-13
        • 1970-01-01
        相关资源
        最近更新 更多