Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/260.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 设置仅获取属性值的首选方法:构造函数vs备份字段_C#_Properties_Class Design - Fatal编程技术网

C# 设置仅获取属性值的首选方法:构造函数vs备份字段

C# 设置仅获取属性值的首选方法:构造函数vs备份字段,c#,properties,class-design,C#,Properties,Class Design,编辑:虽然我已经接受了答案,但也应该考虑答案 设置只读(get only?)属性值的首选方法是:使用备份字段还是使用构造函数?假设设计是针对属性而不是字段的(将来可能会有更新要求属性具有setter,这将阻止使用字段) 给出以下简单示例,首选哪种方法?如果一个比另一个更受欢迎,为什么 选项1(支持字段): class SomeObject { // logic } class Foo { private SomeObject _myObject; public Some

编辑:虽然我已经接受了答案,但也应该考虑答案

设置只读(get only?)属性值的首选方法是:使用备份字段还是使用构造函数?假设设计是针对属性而不是字段的(将来可能会有更新要求属性具有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
    }
}
class SomeObject
{
    // logic
}

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

    public Foo()
    {
        MyObject = new SomeObject();
        // logic 
    }
}
选项2(构造函数)

class SomeObject
{
    // logic
}

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

    public Foo()
    {
        // logic
    }
}
class SomeObject
{
    // logic
}

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

    public Foo()
    {
        MyObject = new SomeObject();
        // logic 
    }
}

这取决于“newsomeobject();”所需的时间以及调用getter的可能性

如果创建MyObject的成本很高,并且不会在每次创建Foo()实例时使用,那么选项1是一个好主意,这称为延迟初始化。像谷歌Chrome这样的程序大量使用它来减少启动时间


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

我个人会做第一件事,但将初始化移到构造函数

class Foo
{
    private SomeObject myObject;

    public SomeObject MyObject
    {
        get { return myObject; }
    }

    public Foo()
    {
        myObject = new SomeObject();
    }
}
为什么??我个人不使用
私有集
,只是因为我必须记住哪些属性有支持变量,哪些没有,这意味着在整个类代码中,一些字段使用小写和大写。我想,这些小小的“矛盾”困扰着我的强迫症自我


不过,这只是一个次要的风格偏好。一个六个,另一个半打。我并不反对选项2,也不反对
私有集
的习惯用法。

我最近偏爱这种方法:

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

    public Foo()
    {
        MyObject = new SomeObject();
    }
}

在许多情况下,我喜欢使类型不可变。在可能的情况下,我喜欢使它们适当地不可变,这意味着完全避免自动实现的属性——否则类型在同一个类中仍然是可变的,这感觉就像一个等待发生的bug

“适当的”不变性将包括使支持字段为只读,这意味着您必须在构造函数中设置它。。。通常从另一个参数初始化它。我发现,像您在问题中所做的那样,在没有更多信息的情况下懒洋洋地创建一个实例是非常罕见的。换句话说,对我来说,这是一种更常见的模式:

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

    public Person(string name)
    {
        this.name = name;
    }
}
当您有很多属性时,这会变得很难处理-将它们全部传递到单个构造函数可能会让人恼火。这就是您希望使用builder模式的地方,使用一个可变类型来收集初始化数据,然后一个构造函数只使用builder。或者,C#4中提供的命名参数和可选参数会使这一过程稍微容易一些

为了回到你的真实情况,我通常会写:

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

    public Foo()
    {
        myObject = new MyObject();
        // logic 
    }
}
也就是说,除非构建
SomeObject
特别昂贵。这比在属性中懒洋洋地执行更简单,而且可能需要担心线程问题

现在,我一直假设不变性在这里是一个有用的目标,但您一直在谈论添加setter。我不知道你为什么认为这会妨碍使用字段,但它肯定不会。例如,您可以将第一段代码中的惰性实例化与如下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
    }
}
我认为主要的决定应该是:

  • 是否希望该类型正确地不可变
  • 您需要延迟初始化吗
  • 您的属性中是否需要其他逻辑

如果所有这些问题的答案都是“否”,请使用自动实现的属性。如果第三个答案变为“是”,您可以随时在以后将自动实现的属性转换为“正常”属性。

这到底有什么好处?它总是初始化myObject(丢失任何延迟加载),并且毫无理由地避免自动道具。如果这是重要的,那么选项2将是不可能的。@John-你是对的,问题的重点并不是关于惰性初始化;相反,首选的方法是什么。。。我最近也在做分配。你也可以在内部进行分配。