【问题标题】:Instance subclass field using parent protected constructor使用父受保护构造函数的实例子类字段
【发布时间】:2016-01-26 15:01:32
【问题描述】:

简化情况

public class A {
    protected A() { }
    protected A Make() { return new A(); }
}

public class B : A {
    A a = new A(); //inaccessible due to protection level
    B b = new B();

    private B()
    {
        A c = new A();//inaccessible due to protection level
        a = new A(); //inaccessible due to protection level
        a = Make();
    }
}

为什么不能使用 A 类受保护的构造函数在 B 类中创建 A 的实例?

在我看来,受保护的构造函数就像受保护的方法,所以应该可以在子类中运行它。

【问题讨论】:

  • 调用基础构造函数可以private B() : base()
  • 能否提供完整的错误信息?
  • hm,我收到另一个错误:无法通过“A”类型的限定符访问受保护的成员“A.A()”;限定符必须是“B”类型(或派生自它)
  • VS Community 2015 中的完整消息:“错误 CS0122 'A.A()' 由于其保护级别而无法访问”

标签: c# inheritance constructor field protected


【解决方案1】:

为什么不能使用 A 类在 B 类中创建 A 的实例 受保护的构造函数?

不能使用new 修饰符调用受保护的构造函数,因为受保护的构造函数的目的是它只能从派生类点调用视图,因此从“外部”看不到。

编译器不会推断对new A() 的调用是从B 的实例完成的。这就是构造函数语法可用的原因,以保证如何调用基本构造函数的约定。

可以在为B 声明构造函数时调用 A 构造函数:

public B(string foo) : base(foo)

这实际上是代表您为默认构造函数所做的事情。例如:

public class A {}
public class B : A
{
    public B() {}
}

将产生以下 IL:

// Methods
.method public hidebysig specialname rtspecialname 
    instance void .ctor () cil managed 
{
    // Method begins at RVA 0x205a
    // Code size 7 (0x7)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void A::.ctor() <--- This.
    IL_0006: ret
} // end of method B::.ctor

一种骇人听闻的方法(我会避免这样做)是创建这样的实例可以通过 Activator.CreateInstance 重载实现,它接受一个 bool 标志,指示构造函数是非公开的:

var b = (B)Activator.CreateInstance(typeof(B), nonPublic: true);

【讨论】:

  • 但在 OP 中,B 类有基类字段,并尝试初始化它。
  • @Grundy 没错,他不能那样做。这就是我在回答中所说的:)
  • 可能,我只是从你的回答中错过了 main :-) 虽然你只是说调用 A 构造函数作为 B 的基础而不是初始化字段
  • 也就是说我只能通过在子类中使用:base()来使用父类受保护的构造函数?
  • @JCode 是的,你可以。这正是它的用途。
【解决方案2】:

你可以让构造函数Aprotected internal:

public class A
{
    protected internal A() { }
    protected A Make() { return new A(); }
}

因此,类型或成员可以被声明它的程序集中的任何代码访问,或者从另一个程序集中的派生类中访问。

查看此链接了解更多详情:Many Questions: Protected Constructors

【讨论】:

    【解决方案3】:

    protected 成员只能通过派生类(或进一步派生类)类型的实例引用在派生类(子类)中访问。

    这是一个使用方法而不是构造函数的示例:

    class B
    {
      protected void M() { }
    }
    class C : B
    {
      void X()
      {
        M(); // OK, same as this.M()
      }
      void Y(C otherC)
      {
        otherC.M(); // OK
      }
      void Z(B otherB)
      {
        otherB.M(); // compile-time error CS1540
      }
    }
    

    因此,在上面的示例中,您可以在 C 内的 C 上调用 M,但不能在 B 内的 C 内调用 M

    您使用实例构造函数的示例与此类似。 new 对象表达式就像在 new 之后编写的类型的(新)对象上调用实例成员(实例构造函数)。

    【讨论】:

      【解决方案4】:

      尝试修改代码为

      a = this.Make();
      

      希望它可以帮助您更好地理解代码。每MSDN

      受保护的成员可以在其类中访问,也可以通过派生类实例访问。

      所以当您调用this.Make() 时,您访问的是derived class instances 中的protected constructor。当您在class B 中调用new A() 时,当前实例this 和要创建的新实例是两个不同的实例。您实际上是在AA 的派生类之外访问A 的构造函数。

      【讨论】:

      • @Grundy,我没说Make 不行。我希望 OP 在上下文中理解 this
      猜你喜欢
      • 2014-04-22
      • 1970-01-01
      • 2013-10-06
      • 1970-01-01
      • 2016-04-07
      • 2011-10-23
      • 2020-10-02
      • 2011-05-30
      • 1970-01-01
      相关资源
      最近更新 更多