【问题标题】:base() and this() constructors best practicesbase() 和 this() 构造函数最佳实践
【发布时间】:2011-04-17 09:16:41
【问题描述】:

在什么条件下我应该在构造函数的括号之后(甚至在代码中的其他位置)进行 :base():this() 构造函数调用。这些电话什么时候是好的做法,什么时候是强制性的?

【问题讨论】:

  • 抱歉含糊不清......我知道这些电话在做什么。我只是不清楚我应该或必须拨打这些电话的情况。如果我不制作它们,那么我马上就注定要失败,或者会有潜在的错误,或者代码质量差。我最近很头疼,因此我想澄清这些情况。 ——

标签: c# oop inheritance constructor instantiation


【解决方案1】:

: base(...)

如果您省略对基构造函数的调用,它将自动调用默认基构造函数。

如果没有默认构造函数,则必须显式调用基本构造函数。

即使存在默认构造函数,您仍可能希望调用与默认构造函数不同的构造函数。在这种情况下,您可能仍希望使用base(foo, bar) 来调用与基本构造函数不同的构造函数。

我不认为当你想调用基类默认构造函数时省略base() 是一个坏习惯,尽管如果你想明确一点,我认为包含它并没有什么坏处。这是一个品味问题。

: this(...)

此语法允许您在同一类中调用具有不同签名的构造函数。这样做从来都不是强制性的,但有时会很有用。

一个有用的例子是在构造函数中重用公共代码。例如,在 C# 3.5 或之前,您可能希望在构造函数上模拟可选参数:

Foo(int x, int y)
{
     this.x = x;
     this.y = y;
}

Foo(int x) : this(x, 10) {}  // y defaults to 10

现在可以使用 C# 4.0 可选参数,这减少了对这种方法的需求。

在构造函数中重用代码的另一种方法是将其分解为一个静态函数,该函数从每个希望使用它的构造函数中调用。

【讨论】:

    【解决方案2】:

    首先,当它们是强制性的时。

    当类Derived 派生自类Base,并且Base 没有默认(无参数)构造函数时,Derived 必须显式调用base() 并带参数。

    public class Base {
        public Base(int i) { }
    }
    
    
    public class Derived : Base {
        // public Derived() { } wouldn't work - what should be given for i?
        public Derived() : base(7) { }
        public Derived(int i) : base(i) { }
    }
    

    什么时候是好的做法?每当您想调用不同的构造函数时。

    假设您在我之前的示例中将内容添加到 Derived 中的构造函数。

    public class Derived : Base {
        // public Derived() { } wouldn't work - what should be given for i?
        public Derived() : base(7) {
            Console.WriteLine("The value is " + 7);
        }
        public Derived(int i) : base(i) {
            Console.WriteLine("The value is " + i);
        }
    }
    

    你注意到这里的重复了吗?调用 this() 构造函数更简单。

    public class Derived : Base {
        // public Derived() { } wouldn't work - what should be given for i?
        public Derived() : this(7) { }
        public Derived(int i) : base(i) {
            Console.WriteLine("The value is " + i);
        }
    }
    

    【讨论】:

    • 所以最后一个例子中的调用顺序是:base(7),然后是Derived(7),然后是Derived()。换句话说,this(7) 部分本身不会触发base()(假设有这样的基本方法)。对吗?
    • 正确;构造函数总是链式的,每个类都调用其基类的构造函数。使用this,你可以重用这个类的另一个构造函数(它本身将使用base,或者隐式地不带参数或显式地使用);使用base,您可以选择调用哪个基类构造函数。
    【解决方案3】:

    当存在继承时使用base,并且父类已经提供了您想要实现的功能。

    当您想要引用当前实体(或自身)时使用this,当您不想复制已经在另一个构造函数中定义的功能时,在构造函数的标头/签名中使用它。

    基本上,在构造函数的标头中使用 base 和 this 是为了让您的代码保持 DRY,使其更易于维护且不那么冗长

    这是一个绝对没有意义的例子,但我认为它说明了展示如何使用这两者的想法。

    class Person
    {
        public Person(string name)
        {
            Debug.WriteLine("My name is " + name);
        }
    }
    
    class Employee : Person
    {
        public Employee(string name, string job)
            : base(name)
        {
            Debug.WriteLine("I " + job + " for money.");
        }
    
        public Employee() : this("Jeff", "write code")
        {
            Debug.WriteLine("I like cake.");
        }
    }
    

    用法:

    var foo = new Person("ANaimi");
    // output:
    //  My name is ANaimi
    
    var bar = new Employee("ANaimi", "cook food");
    // output:
    //  My name is ANaimi
    //  I cook food for money.
    
    var baz = new Employee();
    // output:
    //  My name is Jeff
    //  I write code for money.
    //  I like cake.
    

    【讨论】:

      【解决方案4】:

      查找“C# 中的构造函数链接”。基本上,它看起来像这样:

      MyClass():base()  //default constructor calling superclass constructor
      {
      }
      
      MyClass(int arg):this()  //non-basic constructor calling base constructor
      {
          //extra initialization
      }
      

      它有助于消除构造函数中的代码重复 - 将它们分成基本部分和特定部分。

      【讨论】:

      • 谢谢。 “构造函数链”这个词我不记得了。
      【解决方案5】:

      当您希望将基类的构造函数作为构造函数的第一条指令自动调用时,您可以使用 :base()。 :this() 类似,但它调用同一个类的另一个构造函数。

      在 base:() 和 this() 中:您可以将常量值或基于构造函数参数的表达式作为参数传递。

      当基类没有默认构造函数(不带参数的构造函数)时,必须调用基构造函数。我不知道 :this() 是强制性的。

      public class ABaseClass
      {
          public ABaseClass(string s) {}
      }
      
      public class Foo : AChildClass
      {
          public AChildClass(string s) : base(s) {} //base mandatory
          public AChildClass() : base("default value") {}  //base mandatory
          public AChildClass(string s,int i) : base(s+i) {}  //base mandatory
      }
      
      public class AnotherBaseClass
      {
          public ABaseClass(string s) {}
          public ABaseClass():this("default value") {} //call constructor above
      }
      
      public class Foo : AnotherChildClass
      {
          public AnotherChildClass(string s) : base(s) {} //base optional
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-01
        • 2021-02-13
        • 2017-09-13
        • 2022-11-04
        相关资源
        最近更新 更多