C# 设置仅获取属性值的首选方法:构造函数vs备份字段
编辑:虽然我已经接受了答案,但也应该考虑答案 设置只读(get only?)属性值的首选方法是:使用备份字段还是使用构造函数?假设设计是针对属性而不是字段的(将来可能会有更新要求属性具有setter,这将阻止使用字段) 给出以下简单示例,首选哪种方法?如果一个比另一个更受欢迎,为什么 选项1(支持字段):C# 设置仅获取属性值的首选方法:构造函数vs备份字段,c#,properties,class-design,C#,Properties,Class Design,编辑:虽然我已经接受了答案,但也应该考虑答案 设置只读(get only?)属性值的首选方法是:使用备份字段还是使用构造函数?假设设计是针对属性而不是字段的(将来可能会有更新要求属性具有setter,这将阻止使用字段) 给出以下简单示例,首选哪种方法?如果一个比另一个更受欢迎,为什么 选项1(支持字段): class SomeObject { // logic } class Foo { private SomeObject _myObject; public Some
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-你是对的,问题的重点并不是关于惰性初始化;相反,首选的方法是什么。。。我最近也在做分配。你也可以在内部进行分配。