【问题标题】:Constructor chaining or use named/optional parameters构造函数链接或使用命名/可选参数
【发布时间】:2016-06-02 03:31:10
【问题描述】:

我是一名非常新的程序员,并且了解我们希望最大限度地减少代码冗余,因此当我们更新时,我们可以尽可能少地进行更改并最大限度地减少错误。

所以我有一个 Student 类,我想要重载构造函数,所以如果我做回链它就像这样。

 public class Student
{
    string name;
    int Id;

    public Student()
    {
    }
    public Student(string name)
    {
        this.name = name;
    }
    public Student(string name, int Id) :this(name)
    {
        this.Id = Id;

但这显然很糟糕,因为我们想要一个构造函数中的所有代码是什么原因?易于阅读?

    public Student() : this(null, 0)
    { }
    public Student(string name) : this(name, 0)
    { }
    public Student(string name, int Id) 
    {
        this.name = name;
        this.Id = Id;
    }

如果我执行此前向链接,那么如果我们添加一个新字段(如字符串专业)会发生什么?如果我进行前向链接,那么我将创建一个带有添加字段的新重载构造函数。但是现在我必须更改所有其他构造函数来调用新的构造函数。如果我进行反向链接,我只需创建一个新的构造函数并调用前一个重载的构造函数。

    public Student(string name, int Id, string major):this(name, Id)
    {
        this.major=major;
    } 

这似乎更好地遵循 OOP,但我教科书中的所有示例都显示了前向链接,并没有说明为什么我不应该使用后向链接。

如果我使用命名/可选参数,那就更容易了。

    public Student(string name = null, int Id = 0, string major = null)
    {
        this.name = name;
        this.Id = Id;
        this.major = major;
    }

如果我需要另一个字段,我只需要编辑唯一的构造函数。这似乎最好遵循 OOP 原则,还是我弄错了?它至少最大程度地消除了代码重复。我的任务是“按照 OOP 的原则实施学生课程”。我知道所有这些都是有效的,但这是编码构造函数的最佳/公认方式之一吗?我缺少的命名/可选参数是否存在缺点?作为一个初学者,有这么多的方式来编写这个代码是非常令人困惑的。

【问题讨论】:

  • 链式构造函数在 C# 之前 可选项中被广泛使用,可选项是在 C# 3.0 中添加的,因此您可以阅读的很多信息仍然使用它们,因为它们是旧信息,但今天,带有可选参数,如果在链上你只是传递默认值,链式构造函数就失去了意义。
  • 古斯曼所说的。此外,您可以一次向前链一步:public Student() : this(null) {} 而不是public Student() : this(null, 0) {}。 (尽管如果您有两个采用单个可为空参数的构造函数,这可能会变得模棱两可)。这样,您只需在添加新字段时更改链中的最后一个 c'tor。

标签: c# parameters constructor chaining named


【解决方案1】:

没有最好的方法,因为它们各不相同,各有优缺点。

从 C# 1.0 开始可以使用独立构造函数和链式构造器,在大多数情况下我们使用链式构造器,但如果两个构造器处理完全不同的事情,有时我们必须使用前者。

class Student
{
    public Student()
    {
        DoSomething();
    }

    public Student(string name)
    {
        this.Name = name;
        DoAnotherThing();
    }
}

与可选参数构造函数相比,上面两个要长得多,但说实话,它们要安全得多。考虑以下情况:

public class Student
{
    public Student(string firstName = null, string lastName = null)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

//it's working fine
//var danny = new Student("danny", "chen");

//as the business grows a lot of students need a middle name
public Student(string firstName = null, string middleName = null, string lastName = null)
{
    this.FirstName = firstName;
    this.MiddleName = middleName;
    this.LastName = lastName;
}

//for a better sequence the programmer adds middleName between the existing two, bang!

它们之间的另一个区别是使用反射。可选参数不会为您生成更多的构造函数,如果您使用反射调用构造函数,则不会应用默认值。

【讨论】:

    【解决方案2】:

    我知道所有这些都是有效的,但一种方式是编码构造函数的最佳/公认方式吗?

    据我所知,您有很多选择。您的同事是最适合与之交谈以达成共识的人。 C# 正在成为一种非常丰富的语言,这意味着将有许多不同的方法来实现相同的目标。

    我缺少的命名/可选参数是否存在缺点?

    据我所知,不是。我个人认为这是最好的解决方案,但其他人可能会有所不同。

    作为一个初学者,有这么多的编码方式,这让我很困惑。

    欢迎来到编程。我们有数以百万计的程序员,我们都忙于给世界增加复杂性!

    【讨论】:

      【解决方案3】:

      我建议深入了解这个假设:

      “但这显然很糟糕,因为我们想要一个构造函数中的所有代码,出于什么原因”

      Fluent Interface Pattern 将这些东西分开,我也不能强烈认为这直接转化为构造函数。

      customer
          .NameOfCustomer("Shiv")
          .Bornon("12/3/1075")
          .StaysAt("Mumbai");
      

      说明性实现:

      public class Customer
      {
          public string FullName { get; set; }
          public DateTime DateOfBirth { get; set; }
          public string Address { get; set; }
      
          public Customer NameOfCustomer(string name)
          {
              this.FullName = name;
              return this;
          }
      
          public Customer BornOn(DateTime dateOfBirth)
          {
              this.DateOfBirth = dateOfBirth;
              return this;
          }
      
          public Customer StaysAt(string address)
          {
              this.Address = address;
              return this;
          }
      } 
      

      Example source

      【讨论】:

        【解决方案4】:

        这是部分答案。您的“反向链接”,一个构造函数设置一些参数,然后为其余的调用另一个构造函数,对于普通 函数 来说是非常合理/明智的:一个函数完成部分工作,然后调用另一个其他工作的功能,等等。

        但是对于公共构造函数,其中任何一个都可以被客户端代码调用,期望得到一个完全初始化的完全构造的对象。您的示例中的某些构造函数使成员未初始化(除非您想要的是该类型的默认值)。

        作为替代方案,您可以使用 私有 构造函数。

        【讨论】:

          猜你喜欢
          • 2012-03-14
          • 2015-07-14
          • 2012-01-01
          • 1970-01-01
          • 2019-02-26
          • 2021-05-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多