简体   繁体   English

按需还是在构造函数中创建属性对象?

[英]Create property object on demand or in constructor?

What is the best way of initializing objects for properties without setters in C#? 在C#中初始化没有设置方法的属性的对象的最佳方法是什么?

For example I have property of type UserData and I can initialize it: 例如,我具有UserData类型的属性,可以对其进行初始化:

  1. In constructor 在构造函数中
  2. In getter 吸气剂

     private UserData _user; public UserData User { get { return _user?? (_user= new UserData ()); } } 
  3. Initialize field: 初始化字段:

    private UserData _user = new UserData()

I found few similiar threads: 我发现了一些相似的线程:
Create an object in the constructor or at top of the class 在构造函数中或类的顶部创建一个对象
C# member variable initialization; C#成员变量初始化; best practice? 最佳实践?

But it is consideration between 1st and 3rd option - no one thinks about 2nd option - do you know way? 但这是第一种和第三种选择之间的考虑-没有人考虑第二种选择-你知道吗? From some time it is my preffered option to get objects, but I wonder if there are some cons that I don't know. 从某个时候开始,我倾向于选择获取对象,但是我想知道是否存在一些我不知道的缺点。

Could you tell me what is the best option and what problem could make use of 2nd option? 您能告诉我什么是最好的选择,什么问题可以利用第二个选择?

It all depends on what you want to do with it, so there is definite answer for that. 这完全取决于您要使用它的方式,因此有明确的答案。

One difference between 1+3 and 2 is predictability. 1 + 3与2之间的差异之一是可预测性。
With 1+3, you know exactly where your object is created and at which point during instantiation of your class. 使用1 + 3,您可以确切地知道在哪里创建对象以及在实例化类时的哪个点。 That can be desirable in some circumstances. 在某些情况下,这可能是理想的。
With 2, you depend on external influences (who accesses the property at which time) to initialize the field. 使用2,您需要依靠外部影响力(谁当时访问属性)来初始化字段。

With the delayed creation in approach 2 (only create the object if needed), you could save some time when creating an object of the containing class. 使用方法2中的延迟创建(仅在需要时创建对象),可以在创建包含类的对象时节省一些时间。

If the UserData 's creation takes a lot of time, like, when you have to query a database for it, you might want to delay its creation until really necessary. 如果UserData的创建花费大量时间,例如,当您不得不查询数据库时,您可能希望将其创建延迟到真正需要的时候。 The object that contains the UserData object is constructed faster since it doesn't need to wait for the UserData object to be created. 包含UserData对象的对象构造得更快,因为它不需要等待UserData对象的创建。 If the property isn't always accessed, you might even get to completely avoid creating a UserData instance. 如果不总是访问该属性,您甚至可以完全避免创建UserData实例。

If you're simply using plain data, initializing the backing field at its definition (if possible) is preferred: 如果仅使用普通数据,则最好在其定义处初始化后备字段(如果可能):

// when you create constructor N+1, no worries about forgetting to set the value
private UserData _userData = new UserData();

public UserData User
{
    get { return _userData; }
}

If you need initialization to be deferred, your best option is using Lazy<T> : 如果需要推迟初始化,最好的选择是使用Lazy<T>

private Lazy<UserData> _userData = new Lazy<UserData>(() => new UserData());

public UserData User
{
    get { return _userData.Value; }
}    

The constructor for Lazy<T> contains overloads which can address your thread safety needs: Lazy<T>的构造函数包含重载,可以满足您的线程安全需求:

  • None : access from multiple threads is "undefined behavior" None :来自多个线程的访问是“未定义的行为”
  • PublicationOnly : the first thread to complete initialization "wins" PublicationOnly :完成初始化的第一个线程“获胜”
  • ExecutionAndPublication : locks ensure only one thread initializes the value ExecutionAndPublication :锁确保只有一个线程初始化该值

One issue with #2 is if the property could be accessed by multiple threads you could potentially create two copies of the UserData object. #2的一个问题是,如果该属性可以被多个线程访问,则可能会创建UserData对象的两个副本。 An additional consideration with #2 is if UserData is expensive to create you will be paying the cost of creating that object when the property is accessed rather than when the containing object is created. #2的另外一个考虑因素是,如果UserData的创建成本很高,则您将在访问属性时(而不是在创建包含对象时)承担创建该对象的费用。 That may or may not be desirable depending on your use case. 根据您的用例,这可能是理想的,也可能不是理想的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM