.NET中的隐式链构造函数

本文关键字:构造函数 NET | 更新日期: 2023-09-27 18:28:41

为什么基类没有隐式链构造函数?

我的意思是什么?让我们看看以下类:

class Person
{
    public String Name { get; set; }
    public Person(string name)
    {
        Name = name;
    }
}
class EnhancedPerson : Person
{
    public int Age { get; set; }
}

如果您尝试编译此代码,它将无法编译。正如您所看到的,Person依赖于一个名称,并且清楚地表明,如果没有Name,就不会构造Person

为什么没有隐式EnhancedPerson构造函数,它为每个Person构造函数链接到基构造函数?

只是为了反驳:我开始问自己这个问题,创建具有可注入依赖关系的控制器,因为其中一些依赖关系存在于我的所有控制器中(我想明确指出它们是必要的),我创建了一个基类,我发现重新创建所有构造函数是非常烦人的。。。

附言:我确实知道还有一些其他的编程模式,比如有一个公共的无参数构造函数和依赖关系的公共属性,但是。。。那是另一回事了。

我不是在寻找重新实现这一点的方法,我只是想理解为什么这不可能或为什么没有做到。

.NET中的隐式链构造函数

也许我在这里很天真,但这是我对的理解

样本1

class Person
{
    public String Name { get; set; }
    public Person(string name)
    {
        Name = name;
    }
}

示例1表示创建Person对象的唯一有效方法(根据Person类的作者)是提供Name

样本2

class EnhancedPerson : Person
{
    public int Age { get; set; }
}

示例2表示EnhancedPerson继承了Person的所有数据。

这就是当编译器遇到第一次使用时,我将如何可视化试图构建该代码的编译器

让我们创建一个EnhancedPerson对象。嗯,我需要创建一个人对象。好的,让我们创建一个人对象。创建Person的唯一有效方法是提供名称。那么,让我们看看EnhancedPerson是否告诉了我我应该为Person提供构造函数吗。开枪,它没有。停止错误

总结:要构建EnhancedPerson,您需要构建Person,只有当您提供Name时才能构建

有两种常见的修复方法:

  1. Person中添加一个默认构造函数,这样编译器就可以创建一个"默认初始化"对象请记住,如果类不包含任何其他构造函数,编译器只提供默认构造函数

样本3

    public Person() {
    }
  1. EnhancedPerson添加一个构造函数,该构造函数可以为Person子对象提供Name。以下是几种方法

样品4

    class EnhancedPerson : Person {
        public int Age { get; set; }
        public EnhancedPerson(string name) : base(name) { }
    }
    class EnhancedPerson : Person {
        public int Age { get; set; }
        public EnhancedPerson() : base(null) { }
    }

注意:编译器无法自动推断Name的值为null(因为Person构造函数明确请求它。

演示编译器猜测问题的示例

在下面的示例中,假设txt以字符串形式包含年龄值。您可以看到,如果编译器自动将其传递给Person,我们可能会遇到什么灾难,因为基类只有一个构造函数,它接受字符串,而EnhancedPerson没有任何字符串属性。即使一个拥有所有智力的人必须将hand compile传递给它(而不是EnhancedPerson的作者),他们也无法判断txt是否必须传递给Person构造函数

样品5

class EnhancedPerson : Person {
    public int Age { get; set; }
    public EnhancedPerson(string txt) {
    }
}

我希望现在很清楚为什么当基类构造函数需要参数时,编译器不能自动推断如何链接构造函数。不同的语言提供了不同的机制来指定哪个参数需要传递给基构造函数。

"真正"的原因只能由定义语言的人来回答,但我可以推测。。。

有各种编译时错误可以自动解决,例如:

int mul(int c, int n) {
  int total = 0;
  for(i = 0; i < n; i++) {
    total += c;
  return total
}

上面的代码有3个错误,有3个明显的解决方案:

  1. i未定义
    编译器可以很容易地将i推断为int类型,并且是for语句的本地类型
  2. for块缺少右大括号
    编译器可以"聪明一点",并知道缺少的括号在return ...语句之前,仅仅因为将return作为for块的一部分而不进行任何分支是没有意义的
  3. return total缺少分号
    显然,在编译时"自动更正"很简单

那么编译器为什么不这么做呢?为什么这种情况在任何语言中都不会发生呢
原因很简单,就是没有正当理由,这很危险。是的,这些似乎都是针对被忽视的小错误或细节的逻辑解决方案,但事实上,让编译器解决这些类型的问题可能会导致许多无法解释的行为(如果开发人员真的想在第一次迭代后返回呢?)。另一方面,而不是解决这些问题并提醒它们的成本相当低廉。它让开发人员确切地知道哪里出了问题,如果解决方案真的那么简单,那么只需几分钟就可以手动纠正。

这里的权衡很容易选择,为开发人员提供足够的信息,以便快速解决问题,不留任何机会!

问题中提出的"隐式继承构造函数"也是如此。。。是的,编译器可以很容易地做到这一点。。。但是,如果开发人员真的想在构造函数中做一些真正的工作,但却忘记了呢?编译器不应该通过错误退出编译来提供帮助吗?

假设您有一个带有两个(参数化)构造函数的基类。您的继承类不希望使用其中一个构造函数。

现在,您需要发明新的语法,以便能够说"不要让他们使用这个构造函数"。而"让我定义一个构造函数,并作为其中的一部分,选择要调用的基类构造函数"是一个通常有用的构造,您无论如何都希望在该语言中使用它。