【问题标题】:Beginner to C#: How to do constructor chaining, overriding and using :this / :base?C# 初学者:如何进行构造函数链接、覆盖和使用 :this / :base?
【发布时间】:2017-07-27 08:10:58
【问题描述】:

我去年学习了 Java,我认为我在编写构造函数方面从来没有遇到过问题。不幸的是,我对 C# 中的重载和链接是如何工作的,甚至是它的基本概念感到困惑。

我已经看到 :base 被用于继承,但我不确定如何。 我见过:这在很多地方都得到了使用,而且它总是让我感到困惑,为什么要使用它。

下面是一些带有 :this 的代码示例(为了论证而制作了没有 setter/getter 的公共变量)。

public class Person
{
    public string firstName;
    public string lastName;
    public string height;
    public int age;
    public string colour;

public Person():this("George", "Seville", "45cm", 10, "Black")
    {
    // This is the default constructor, and we're defining the default 
values.
     }

public Person(string firstName, string lastName, string height, int age, 
string colour)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.height = height;
        this.age = age;
        this.colour = colour;
    }

}}

我只能理解如何使用第一个构造函数,例如制作一个简单的“Person”对象会给它默认值。这是我能理解的。此代码未完成,因为它显示了 2 个默认构造函数。我希望能够为每个可用的变体重载和链接,即 1 个参数,2 个参数......所以它们都可以适当地重载和链接。

所以它应该有点(可能不正确)看起来像这样:

public Person():this("George", "Seville", "45cm", 10, "Black")
    {
    // This is the default constructor, and we're defining the default 
values.
     }

public Person(string firstName):this(firstName, "George", "Seville", "45cm", 
10, Black)
    {
        this.firstName = firstName;
    }

public Person(string firstName, string lastName):this(firstName, lastName, 
"Seville", "45cm", 10, Black)
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }

当然,我不确定上面的任何代码是否有意义,但我已经看到一些类的构造函数都带有 :this,并且每个构造函数都链接到它下面的一个,直到用户可以创建定义了任意参数组合的对象。

至于 :base,这完全让我感到困惑。这是我在网上找到的一个例子:

    public class Circle:Shape
{
    public Circle():this(Color.Black, new Point(0,0), 1)
    {
    }

    public Circle(Color Colour, Point Position, double Radius):base(Colour, 
Position) 
    {
        this.Radius = Radius;
    }

我认为 :base 指的是父类,但我不确定为什么以及如何。另外,为什么在第一个构造函数中使用 :this 而不是 :base?

有两个方面我很困惑。使用 :this 和 :base 并准确理解构造函数链接和重载的工作原理。如果我的问题太抽象,请告诉我。我尽量做到具体。

非常感谢大家的支持和时间。非常感谢!

【问题讨论】:

  • 在最后一个中,调用 this 调用 Circle 中的构造函数,然后该构造函数调用 Shape 中的基构造函数,该构造函数采用 Color 和 Position。
  • 您可以为参数提供默认值,因此不需要提供。这样你就可以用一堆可选参数编​​写 1 个构造函数。
  • this关键字用于调用同一类的构造函数,base关键字用于调用基类或父类的构造函数。在您的最后一个示例中,您的默认构造函数正在调用 Circle 类的重载构造函数,而重载构造函数正在调用 Shape 类的参数化构造函数。此外,base 关键字也可以用于调用基类或父类的任何方法。
  • 如果您了解 Java 并且对 Java 感到满意,也许这与您相关:Inheritance and Derived Classes (C# vs Java) 特别关注 C# 和 Java 在继承和派生类方面的异同。

标签: c# inheritance constructor overloading chaining


【解决方案1】:

我会尽量简单地解释它。

构造函数重载

这里没有什么新东西,就像重载任何其他方法一样 - 您只需要相同的名称但不同的签名(意味着传递给构造函数的参数不同)。

构造函数链

这是通过使用关键字 this 完成的 - 就像您问题中的代码示例一样。
顺便说一句,我通常用它来从最复杂的构造函数变成最简单的构造函数。
示例代码:

public class Person
{
    public Person()
    {
        Children = new List<Person>();
    }

    public Person(string firstName)
        : this()
    {
        this.FirstName = firstName;
    }

    public Person(string firstName, string lastName)
        : this(firstName)
    {
        this.LastName = lastName;
    }

    public string FirstName { get; }
    public string LastName { get; }
    public IEnumerable<Person> Children { get; }
}

当然,通过使用构造函数链接为属性设置默认值是一种有效的设计,我在需要时自己使用过,但通常情况并非如此。

关键字base

这个关键字总是指基类(或父类)。 在覆盖方法和属性时,您也会看到很多。
当涉及到构造函数时——你的假设是正确的——它确实指的是基类(或父类)。 因此,当在构造函数中使用时(例如在您的 Circle 示例中),您可以控制派生(或子)类构造函数将执行的基构造函数的重载。
因此,例如,如果您的基类包含三个构造函数,您可以选择要调用其中的哪一个。

除非另有说明,否则c#会将派生类的构造函数链接到基类的默认构造函数。
请注意,如果您从没有默认(即:无参数)构造函数的类继承,则必须在构造函数中指定 : base(...),即使基类只有一个构造函数(因为这是您可以传递的唯一方法所需的参数)。

【讨论】:

  • 谢谢!我认为我的困惑源于“:this”的使用。在 Java 中,我从来没有真正想要设置默认值,因为我的所有对象都是用于初始化并填充参数的。非常感谢!
【解决方案2】:

一般来说: this(...)指的是当前类的构造函数。如您的示例所示,这可用于避免代码重复。从逻辑的角度来看,我认为给出的示例没有太大意义,但它是合法的 C# 并且 - 基本上 - 如何使用 : this(...)

第二个例子是一个更合乎逻辑或连贯性的例子,因为默认构造函数提供了合理的默认值来传递给参数化构造函数。

这是默认构造函数,它为要传递给参数化构造函数的值创建合理的默认值:

public Circle():this(Color.Black, new Point(0,0), 1)

这是参数化构造函数,它将基类也需要的参数传递给Shape的构造函数:

public Circle(Color Colour, Point Position, double Radius):base(Colour, Position) 

如果你需要一个标准的圆圈,你可以创建一个

var shape = new Circle();

另一方面,如果您需要在特定位置、具有特定颜色和特定半径的圆,您可以使用参数化构造函数创建一个

var shape = new Circle(Color.Silver, new Point(1,2), 5);

【讨论】:

    【解决方案3】:

    我认为 :base 是指父类,但我不确定为什么以及如何

    base是访问父类成员的关键字。

    1) var p = base.Property; 将访问父类中的字段或属性

    2) base.Method(); 将访问父类中的方法

    3) base(..) 将访问父类的构造函数

    为什么在第一个构造函数中使用 :this 而不是 :base?

    this 是访问同一类成员的关键字。有 3 个参数定义了 Circle 的属性。 CircleShape 仅共享 1 个属性:color。所以默认构造函数调用同一个类的更专业的构造函数Circle(这就是this()的原因),第二个构造函数将共享属性color传递给父类进行处理。

    public class Circle:Shape
    {
        public Circle():this(Color.Black, new Point(0,0), 1)
        {
        }
    
        public Circle(Color Colour, Point Position, double Radius):base(Colour, 
    Position) 
        {
            this.Radius = Radius;
        }
    }
    

    【讨论】:

      【解决方案4】:

      在您的示例中,“base”是指形状(颜色,点位置),“this”是指圆形(颜色,点位置,双半径)。

      【讨论】:

        【解决方案5】:

        第一个构造函数正在访问定义中的第二个构造函数,这就是它使用 :this 的原因。

        第二个构造函数是使用基类中定义的构造函数,这就是它使用基类的原因:

        如果您使用以下方法创建 Circle 实例:

        Circle()
        

        它将使用第一个构造函数,该构造函数将调用第二个构造函数(添加所需的参数),该构造函数将调用基类中的构造函数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-21
          • 2011-04-17
          • 1970-01-01
          • 2014-04-11
          相关资源
          最近更新 更多