应该在课堂上自动设置对象的成员吗?

问题描述:

当你有一个复杂的属性,你应该实例化它还是让它给用户来实例化它?应该在课堂上自动设置对象的成员吗?

例如(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是唯一可以修改名称集合的地方。

我已经在少数情况下实现了这个功能,但是当我为所有事情做的时候,它会与其他程序员产生太大的摩擦。

+0

与XmlSerialization的部分是不完全正确也没关系。如果您使用[XmlArray]声明了一个集合属性,那么它只能是只读或{get;}。因此,您的评论仅适用于[XmlArray]不支持的属性类型。 – OregonGhost 2008-10-30 13:43:23

这真的取决于。

如果该类应该使用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); 
    } 
} 

现在,如果你使用一个列表,哈希表,字典等