应该在课堂上自动设置对象的成员吗?
当你有一个复杂的属性,你应该实例化它还是让它给用户来实例化它?应该在课堂上自动设置对象的成员吗?
例如(C#)
A)
class Xyz{
List<String> Names {get; set;}
}
当我尝试使用,我必须将其设置。
...
Xyz xyz = new Xyz();
xyz.Name = new List<String>();
xyz.Name.Add("foo");
...
在哪里,如果我修改代码
B)
class Xyz{
public Xyz(){
Names = new List<String>();
}
List<String> Names {get; }
}
在这种情况下,我可以让列表只读。
另一种情况可能会出现,我想你会故意不想设置它。例如,在
C)
class Xyz{
String Name {get; set;}
}
我会的东西做不好的做法来初始化。
这种情况下是否存在一些经验法则?
这是我正常的解决方案:
class XYZ
{
public XYZ() { Names = new List<string>(); }
public List<string> Names { get; private set; }
}
(需要注意的是它不与XmlSerialization工作,因为你需要在所有XmlSerialized属性getter和setter)(您可以覆盖这一点,但它似乎像很少的工作一样工作)。
由于OregonGhost指出 - 您需要添加[XmlArray]
为此以使用XmlSerialization。
这仍然打破封装的规则,如果你想完全正确,你会:
class XYZ
{
public XYZ() { AllNames = new List<string>(); }
private List<string> AllNames { get; set; }
public void AddName (string name) { AllNames.Add(name); }
public IEnumerable<string> Names { get { return AllNames.AsReadOnly(); } }
}
由于这违背了几乎所有的.NET Framework的其余部分的设计,我通常最终使用第一种解决方案。
但是,这具有额外的好处,即XYZ可以跟踪对其名称集合的更改,并且XYZ是唯一可以修改名称集合的地方。
我已经在少数情况下实现了这个功能,但是当我为所有事情做的时候,它会与其他程序员产生太大的摩擦。
这真的取决于。
如果该类应该使用null属性正确运行,则可以将其保留为未初始化状态。否则,你最好在构造函数中初始化它。
而且,如果你不希望房地产建设后要改变,你可以把它私人
class Xyz
{
public Xyz(string name)
{
this.Name = name;
}
String Name
{
get;
private set;
}
}
作为一个经验法则(意味着总是会有来自该规则的例外)设置你的成员在构造函数中。这就是构造函数的用途。
记住beind OO是抽象的想法之一。要求'用户'(即程序员谁想要在他的源代码中实例化你的对象)这样做是 违反抽象原则。在使用你的对象之前,用户必须考虑一件事情,因此还有一个可能的错误来源。
是的,有经验法则。代码分析工具对此是一个好的开始。
问题有关代码的一些经验法则:
它不好的做法,允许对集合属性setter方法。这是因为它很容易处理空集合,就像代码中的完整集合一样。强迫人们对收集进行空检查会让你挨打。考虑下面的代码片段:
public bool IsValid(object input){
foreach(var validator in this.Validators)
if(!validator.IsValid(input)
return false;
return true;
}
此代码的工作原理是否验证器的集合为空或不是。如果您希望进行验证,请将验证程序添加到集合中。如果不是,则将该集合留空。简单。允许收集属性为空结果在上面的这个臭的代码版本:
public bool IsValid(object input){
if(this.Validators == null)
return false;
foreach(var validator in this.Validators)
if(!validator.IsValid(input)
return false;
return true;
}
更多的代码行,不那么优雅。其次,对于参考类型而不是集合,您必须考虑对象在确定是否要设置属性值时的行为方式。这个属性是否有一个明显的默认值?或者该属性的空值是否具有有效含义?
在您的示例中,您可能希望始终在setter中检查Name值,并在分配空值时将其设置为默认的“(无名称给定)”。这可能会使绑定此对象对UI时更容易。或者,名称可能为空,因为您需要一个有效的名称,并且当调用者试图在未首先设置名称的情况下对对象执行操作时,您将检查它并抛出InvalidOperationException。
与编程中的大多数事情一样,有一些不同的方式可以做某些事情,其中一半是坏的,另一半只有在某些情况下才行。
构造函数的目的是构造构造的对象。不需要进一步的“设置”。如果是在调用者知道一些信息,那么应该传递给构造函数:
错误:
MyClass myc = new MyClass();
myc.SomeProp = 5;
myc.DoSomething();
右:
MyClass myc = new MyClass(5);
myc.DoSomething();
这是特别真实如果需要将SomeProp设置为myc以处于有效状态。
如果可能,你应该尝试封装你的数据。将对象公开为列表需要用户知道关于该类的太多私密细节。例如,他们必须知道他们是否必须从头创建列表以避免空引用异常。
public class Xyz
{
private List<String> _names = new List<String>(); // could also set in constructor
public IEnumerable<String> Names
{
get
{
return _names;
}
}
public void AddName(string name)
{
_names.Add(name);
}
}
现在,如果你使用一个列表,哈希表,字典等
与XmlSerialization的部分是不完全正确也没关系。如果您使用[XmlArray]声明了一个集合属性,那么它只能是只读或{get;}。因此,您的评论仅适用于[XmlArray]不支持的属性类型。 – OregonGhost 2008-10-30 13:43:23