设置get only属性值的首选方法:构造函数与支持字段

Met*_*urf 3 c# class-design properties

编辑:虽然我接受了大卫的回答,但乔恩的回答也应该被考虑.

设置只读(仅获取?)属性的值首选哪种方法:使用支持字段还是使用构造函数?假设设计是针对属性而不是字段(将来,可能会有更新要求属性具有可以排除使用字段的setter).

鉴于以下简单示例,首选哪种方法?如果一个优先于另一个,为什么?

选项1(支持领域):

class SomeObject
{
    // logic
}

class Foo
{
    private SomeObject _myObject;
    public SomeObject MyObject
    {
        get
        {
            if( _myObject == null )
            {
                _myObject = new SomeObject();
            }
            return _myObject;
        }
    }

    public Foo()
    {
        // logic
    }
}
Run Code Online (Sandbox Code Playgroud)

选项2(构造函数):

class SomeObject
{
    // logic
}

class Foo
{
    public SomeObject MyObject { get; private set; }

    public Foo()
    {
        MyObject = new SomeObject();
        // logic 
    }
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*vid 7

它取决于"new SomeObject();"所需的时间.以及将要调用吸气剂的可能性.

如果创建MyObject的成本很高,并且每次创建Foo()的实例时都不会使用它,那么选项1是个好主意,这就是所谓的延迟初始化.Google Chrome等程序会大量使用它来缩短启动时间.

如果您每次都要创建MyObject,并且经常调用getter,那么您将使用选项2保存每次访问的比较.


Jon*_*eet 5

在许多情况下,我喜欢使类型不可变.如果可能的话,我喜欢让他们正确地不变,这意味着避免自动实现的属性完全-否则的类型仍然是同一个班级,感觉就像一个等待发生的错误内可变.

"正确"的不变性将包括使备份字段只读,这意味着您必须在构造函数中设置它...通常从另一个参数初始化它.我发现很少有我可以懒得创建一个没有任何更多信息的实例,就像你在问题中所做的那样.换句话说,这对我来说是一种更常见的模式:

public class Person
{
    private readonly string name;
    public string Name { get { return name; } }

    public Person(string name)
    {
        this.name = name;
    }
}
Run Code Online (Sandbox Code Playgroud)

当你拥有很多属性时,这会变得笨拙 - 将它们全部传递给单个构造函数会让人讨厌.这就是你想要使用构建器模式的地方,一个用于收集初始化数据的可变类型,然后是一个只接受构建器的构造函数.或者,C#4中提供的命名参数和可选参数应该使这更容易一些.

为了回到你的确切情况,我通常写道:

class Foo
{
    private readonly MyObject myObject;
    public SomeObject MyObject { get { return myObject; } }

    public Foo()
    {
        myObject = new MyObject();
        // logic 
    }
}
Run Code Online (Sandbox Code Playgroud)

也就是说,除非构造SomeObject特别昂贵.这比在财产中懒散地做起来更简单,并且可能不得不担心线程问题.

现在,我一直认为不变性在这里是一个有用的目标 - 但你一直在谈论添加一个二传手.我不确定你为什么认为这会妨碍使用某个领域,但肯定不会.例如,您可以组合第一段代码中的延迟实例化并使用这样的setter:

class Foo
{
    private SomeObject _myObject;
    public SomeObject MyObject
    {
        get
        {
            if( _myObject == null )
            {
                _myObject = new SomeObject();
            }
            return _myObject;
        }
        set
        {
            // Do you want to only replace it if
            // value is non-null? Or if _myObject is null?
            // Whatever logic you want would go here
            _myObject = value;
        }
    }

    public Foo()
    {
        // logic
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为主要的决定应该是:

  • 你想要类型是否正确不可变?
  • 你需要延迟初始化吗?
  • 您的房产中是否需要任何其他逻辑?

如果所有这些的答案都是否定的,请使用自动实现的属性.如果第三个答案变为是,您可以随后将自动实现的属性转换为"正常"属性.