根据需要或在构造函数中创建属性对象?

时间:2012-07-25 13:56:28

标签: c# .net properties

在C#中没有setter的情况下初始化属性对象的最佳方法是什么?

例如,我有UserData类型的属性,我可以初始化它:

  1. 在构造函数中
  2. 在getter中

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

    private UserData _user = new UserData()

  4. 我发现几个类似的线程:
    Create an object in the constructor or at top of the class
    C# member variable initialization; best practice?

    但是考虑第1和第3选项 - 没有人考虑第2选项 - 你知道吗?从某种程度上来说,获取对象是我的优先选择,但我想知道是否有一些我不知道的缺点。

    你能告诉我什么是最好的选择,什么问题可以使用第二选项?

3 个答案:

答案 0 :(得分:3)

这一切都取决于你想用它做什么,所以有明确的答案。

1 + 3和2之间的一个区别是可预测性 使用1 + 3,您可以确切地知道对象的创建位置以及在类实例化期间的哪个位置。在某些情况下这是可取的 使用2,您可以依赖外部影响(访问该属性的时间)来初始化字段。

使用方法2中的延迟创建(仅在需要时创建对象),可以在创建包含类的对象时节省一些时间。

如果UserData的创建需要花费很多时间,例如,当您必须为数据库查询数据时,您可能希望将其创建延迟到必要时。包含UserData对象的对象构造得更快,因为它不需要等待创建UserData对象。如果不总是访问该属性,您甚至可能完全避免创建UserData实例。

答案 1 :(得分:0)

如果您只是使用纯数据,则首选初始化支持字段(如果可能):

// 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; }
}

如果您需要延迟初始化,最好的选择是使用Lazy<T>

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

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

Lazy<T>的构造函数包含可以解决线程安全需求的重载:

  • None:来自多个线程的访问是“未定义的行为”
  • PublicationOnly:完成初始化“wins”的第一个线程
  • ExecutionAndPublication:locks确保只有一个线程初始化值

答案 2 :(得分:0)

#2的一个问题是,如果多个线程可以访问该属性,则可能会创建UserData对象的两个副本。 #2的另一个考虑因素是,如果创建UserData是昂贵的,那么在访问属性时将支付创建该对象的成本,而不是在创建包含对象时。根据您的使用情况,这可能是也可能不合适。