.NET中的隐式链构造函数

时间:2015-12-30 21:04:48

标签: c# .net constructor language-design roslyn

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

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

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

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

如果您尝试编译此代码,则无法编译。正如您所看到的,Person取决于名称并明确说明,您不会构建Person而不会Name

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

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

P.S。我知道还有其他一些编程模式,比如有一个公共的无参数构造函数和依赖的公共属性,但......那是另一个故事。

我没有找到重新实现这一目标的方法,我只是试图理解为什么它不可能或为什么没有完成。

3 个答案:

答案 0 :(得分:2)

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

示例1

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

示例1 表示创建Person对象的唯一有效方式(根据Person类的作者)是通过提供Name < / p>

示例2

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

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

这是我想象编译器在遇到第一次使用时尝试构建代码的方式

  

让我们创建一个EnhancedPerson对象。好吧,我需要创建一个人   由于继承而导致的对象。好的,让我们创建一个Person   对象然后。好吧,创建Person的唯一有效方法是   提供名称。那么,让我们检查一下EnhancedPerson是否告诉了我什么   我应该为Person提供构造函数。拍,它没有。停下来   错误

总结:要构建EnhancedPerson,您需要构建Person,只有在您提供Name

时才能构建Person

有两种常见的修复方法:

  1. public Person() { } 添加默认构造函数,以便编译器可以创建“默认初始化”对象。 请记住,如果该类不包含任何其他构造函数,则编译器仅提供默认构造函数。
  2. 示例3

    EnhancedPerson
    1. Name添加构造函数,该构造函数可以为Person子对象提供 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) { } } 。以下是几种方法。
    2. 示例4

      Name

      注意:编译器无法自动将Person的值推断为null(因为txt构造函数显式请求它。

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

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

      示例5

      opensaml::SecurityPolicyException
      
      The system encountered an error at Wed Jan 6 00:24:30 2016
      
      To report this problem, please contact the site administrator at root@localhost.
      
      Please include the following message in any email:
      
      opensaml::SecurityPolicyException at (*****/Shibboleth.sso/SLO/Redirect)
      
      Security of LogoutResponse not established.
      

      我希望现在显而易见的是,当基类构造函数需要参数时,编译器无法自动推断如何链接构造函数。不同的语言提供了不同的机制来指定需要将哪个参数传递给基础构造函数。

答案 1 :(得分:1)

“真实”的原因只能由定义语言的人来回答,但我可以推测......

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

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缺少分号
    编译时“自动更正”显然很简单。
  4. 那么编译器为什么不这样做呢?为什么这种情况不会真的发生在任何一种语言中? 嗯,原因很简单,没有正当理由就是危险的。是的,这些似乎都是忽略小错误或细节的逻辑解决方案,但实际上让编译器解决这些类型的问题可能会导致许多无法解释的行为(如果开发人员确实想在第一次迭代后返回该怎么办? )。另一方面,解决这些问题并提醒他们的成本相当便宜。它让开发人员确切地知道出了什么问题,如果解决方案确实如此简单,那么手动纠正的时间应该不多。

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

    同样适用于问题中提出的“隐式继承构造函数”...是的,编译器可以轻松地做到这一点......但是如果开发人员真的想在构造函数中做一些真正的工作,但是忘记?不应该编译器通过错误编译来帮助吗?

答案 2 :(得分:1)

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

您现在需要发明 new 语法,以便能够说'不要让他们使用此构造函数&#34;。而#34;让我定义一个构造函数,并作为其中的一部分,选择要调用的基类构造函数&#34;是一种通常有用的结构,无论如何都要用语言。