【问题标题】:Base Base Constructor C# initializationBase 基本构造函数 C# 初始化
【发布时间】:2014-06-05 17:55:28
【问题描述】:

一个简化的场景。三个类,GrandParent,Parent 和 Child。我想做的是利用 GrandParent 和 Parent 构造函数来初始化一个 Child 实例。

class GrandParent ()
{
    public int A {get; protected set;}
    public int B {get; protected set;}

    public GrandParent (int a, int b);
    {
        A = a;
        B = b;
    }
}

class Parent : GrandParent ()
{
    public Parent () {}
}

Child Class,如果出现问题。

class Child : Parent ()
{
    public int C {get; protected set}

    public Child (int c) // here I want it to also call the GrandParent (int a, int b)
                         // before calling Child (int c)
    {
        C = c;
    }
}

Child = new Child (1,2,3);

我想要的是变量 a、b 和 c 分别获得 1,2 3 作为值。我知道我可以通过简单地将A = aB = b 添加到Child 构造函数来解决它。

这可能吗?如果有怎么办?

我开始查看 base (),但它看起来只能访问 Parent 类而不是 GrandParent

提前致谢。

附言。如果之前有人问过,我提前道歉,我没有找到任何东西。

快速编辑:我正在努力使解决方案尽可能易于使用,以便进一步开发。

【问题讨论】:

  • 为了编译,Parent 不需要一个带两个参数的构造函数吗?
  • 这目前无法编译,我现在使用的是A=aB=b 以及将其参数放入 Child 中。我的问题是没有可能吗?
  • 还有一个语法错误,因为类名后面不应该有括号()
  • 这个故事的寓意是,在解释继承时,我们应该避免使用ParentGrandparentChild 作为示例名称。 child 不是 parent 的类型,parent 不是 grandparent 的类型。这些名称没有充分解释上位词/同音词关系,因此“可以在没有设置 A 或 B 的情况下创建的东西”不能是一种“只能用正在设置 A 或 B”。

标签: c# inheritance


【解决方案1】:

您只能调用直接超类的构造函数。直接超类需要公开您需要的选项。它可以使用protected 构造函数安全地执行此操作。

【讨论】:

  • +1 您发布时正在 MSDN 上验证这一点。 base 总是去找直接的父母。
【解决方案2】:

C# 良好实践假定您在每个孩子中调用基类构造函数。也就是说,您将从父级调用 base(a,b) 并从子级调用 base(a,b),这将调用祖父母 ctor。这使您可以封装。这是你重写的sn-p代码:

class GrandParent ()
{
    public int A {get; protected set;}
    public int B {get; protected set;}

    public GrandParent (int a, int b);
    {
        A = a;
        B = b;
    }
}

class Parent : GrandParent ()
{
    public Parent (int a, int b):base(a,b) {}
}
Child Class, were the problem occurs.

class Child : Parent ()
{
    public int C {get; protected set}

    public Child (int a, int b, int c):base(a,b)
    {
        C = c;
    }
}

【讨论】:

    【解决方案3】:

    您需要通过每个构造函数将变量传递给它的基构造函数:

    class Child : Parent ()
    {
        public int C {get; protected set}
    
        public Child (int a, int b, int c) : base(a,b)
                             // before calling Child (int c)
        {
            C = c;
        }
    }
    
    Child = new Child (1,2,3);
    
    class GrandParent ()
    {
        public int A {get; protected set;}
        public int B {get; protected set;}
    
        public GrandParent (int a, int b);
        {
            A = a;
            B = b;
        }
    }
    
    class Parent : GrandParent ()
    {
        public Parent (int a, int b) : base(a,b) {}
    }
    

    【讨论】:

    • 我也有同样的怀疑,在某种程度上使它更干净。不像我想要的那样干净。
    【解决方案4】:

    parentchild 是有限适用性的类比,因为派生类不是基类的“孩子”,因为人或动物的孩子是它们,甚至作为子目录是树中的目录或依赖节点(GUI 或数据结构)。

    这种关系实际上是上位词与下位词的关系。遗憾的是,hypernym 并不像 parent 那样广为人知,因此人们在解释继承时经常使用不太准确的 parent 而不是上位词

    现在,让我们考虑第一个类声明:

    class GrandParent
    {
        public int A {get; protected set;}
        public int B {get; protected set;}
    
        public GrandParent (int a, int b)
        {
            A = a;
            B = b;
        }
    }
    

    除了第一行错误的() 和第六行的; 已被删除之外,这与问题中的完全相同。

    它有一个构造函数,需要两个整数。

    这意味着:

    1. 在没有传递两个整数的情况下创建 GrandParent 是没有逻辑意义的。
    2. 这是如何定义的错误。
    3. 好的,也许不是错误,但肯定有点懒。

    当我们来到Parent的声明时:

    class Parent : GrandParent
    {
        public Parent () {}
    }
    

    这里我已经修复了语法错误,但没有别的。

    由于在构造函数中没有显式使用base,因此隐含调用了无参数base()。也就是上面的完全一样:

    class Parent : GrandParent
    {
        public Parent()
            : base()
        {
        }
    }
    

    new Parent() 的任何调用都将通过base() 调用new GrandParent()。由于GrandParent() 上没有无参数构造函数,因此无法编译。

    这里的语言规则正在帮助我们:

    1. 我们说过,在不使用两个整数的情况下创建 GrandParent 是没有意义的。
    2. 我们说ParentGrandParent 的一种类型。
    3. 我们说过,Parent 只会在没有设置这两个整数的情况下创建。

    我们说过三件事是真的,但不可能都是真的。语言规则正确指出我们的错误。

    要解决这个问题,我们需要:

    1. 允许创建 GrandParent 而不在其构造中使用这两个整数。
    2. 强制Parents 在其构造中始终使用两个整数,然后依次与基本构造函数一起使用。
    3. Parent 上的无参数构造函数使用一些设置值调用base(a, b)
    4. 混合使用上述方法。例如。如果调用了无参数构造函数,我们可以同时调用设置值,也可以调用另一个将参数传递给基本构造函数的构造函数。

    上面的第三个看起来像:

    class Parent : GrandParent
    {
        public Parent()
            : base(42, -343213)
        {
        }
    }
    

    或者其他什么,只要这些数字来自某个地方(显然在实际代码中,它们会与比我随机输入更合理的东西相关联)。

    现在我们有了一个实际上合乎逻辑的Parent,其余的可以跟进。

    【讨论】:

    • 谢谢。我想我现在明白了。抱歉,小错误,我重写了代码以最小化它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 2011-01-25
    • 1970-01-01
    相关资源
    最近更新 更多