是否应在类中自动设置对象的成员



当你有一个复杂的属性时,你应该实例化它还是留给用户来实例化它?

例如 (C#(

一(

 class Xyz{
     List<String> Names {get; set;}
 }

当我尝试使用时,我必须设置它。

...
Xyz xyz = new Xyz();
xyz.Name = new List<String>();
xyz.Name.Add("foo");
...

好像我修改代码的地方

二(

 class Xyz{
     public Xyz(){
         Names = new List<String>();
     }
     List<String> Names {get; }
 }

在这种情况下,我可以将列表设为只读。

可能会出现另一种情况,我想您故意不想设置它。例如在

(三((

 class Xyz{
     String Name {get; set;}
 }

我会认为初始化是一种不好的做法。

对于这种情况,是否有一些经验法则?

根据经验(意味着该规则总会有例外(,请在构造函数中设置您的成员。这就是构造函数的用途。

请记住,OO的一个想法是抽象。要求"用户"(即想要在他的源代码中实例化你的对象的程序员(这样做是违反了抽象原则。这将是用户在使用对象之前必须考虑的另一件事,因此又是一个潜在的错误来源。

是的,有经验法则。 代码分析工具是这方面的良好开端。

关于相关代码的一些经验法则:

允许集合属性上的资源库是不好的做法。 这是因为在代码中将空集合视为完整集合很简单。 强迫人们对收藏进行空检查会让你挨打。 请考虑以下代码片段:

public bool IsValid(object input){
  foreach(var validator in this.Validators)
    if(!validator.IsValid(input)
      return false;
  return true;
}

无论验证程序集合是否为空,此代码都有效。 如果要进行验证,请将验证程序添加到集合中。 如果没有,请将集合留空。 简单。 允许集合属性为 null 会导致上述代码版本出现:

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;
}

代码行更多,不那么优雅。

其次,对于集合以外的引用类型,在确定是否要设置属性值时,必须考虑对象的行为方式。 属性是否有单个明显的默认值? 或者属性的 null 值是否具有有效含义?

在您的示例中,您可能希望始终在 setter 中检查 Name 值,并在分配 null 时将其设置为默认的"(未给定名称("。 这可能会使将此对象绑定到 UI 时更容易。 或者,该名称可能为 null,因为您需要一个有效的名称,并且当调用方尝试在对象上执行操作而不先设置名称时,您将检查它并引发 InvalidOperationException。

像编程中的大多数事情一样,有很多不同的方法来做某事,其中一半是坏的,另一半的每种方式只在某些情况下是好的。

构造函数的目的是构造对象。 不需要进一步的"设置"。 如果调用方知道一些信息,则应将其传递给构造函数:

错:

MyClass myc = new MyClass();
myc.SomeProp = 5;
myc.DoSomething();

右:

MyClass myc = new MyClass(5);
myc.DoSomething();

如果需要将 SomeProp 设置为使 myc 处于有效状态,则尤其如此。

这是我

的正常解决方案:

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 框架其余部分的设计背道而驰,因此我通常最终使用第一个解决方案。

但是,这确实具有额外的好处,即 XYZ 可以跟踪对其名称集合的更改,并且 XYZ 是唯一可以修改名称集合的位置。

我已经在少数情况下实现了它,但是当我对所有事情都这样做时,它会导致与其他程序员产生太多摩擦。

这真的取决于。

如果类应该使用 null 属性正确运行,则可以将其保留为未初始化。否则,您最好在构造函数中初始化它。

而且,如果您不希望在施工后更改该物业,则可以将其设为私有

class Xyz
{
     public Xyz(string name)
     {
         this.Name = name;
     }
     String Name 
     {
          get; 
          private set;
     }
}

如果可能的话,你应该尝试封装你的数据。将对象公开为列表需要用户了解有关类的太多私密细节。例如,他们必须知道是否必须从头开始创建列表以避免空引用异常。

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 );
   }
}

现在,无论您使用列表,哈希表,字典等都没关系。

相关内容

  • 没有找到相关文章

最新更新