开发者

Why can't subclasses create new objects with a base class protected constructor?

I'm porting some Java code to C#, and I ran into this idiom used to copy objects:

class Base
{
    int x;
    public Base(int x) { this.x = x; }
    protected Base(Base开发者_开发百科 other) { x = other.x; }
}

class Derived : Base
{
    Base foo;
    public Derived(Derived other)
        : base(other)
    {
        foo = new Base(other.foo); // Error CS1540
    }
}

Error CS1540 being:

Cannot access protected member 'Base.Base(Base)' via a qualifier of type 'Base'; the qualifier must be of type 'Derived' (or derived from it)

I understand the purpose of this error: it prevents accessing protected members of sibling types. But Base.Base(Base) is obviously not going to be invoked on a sibling type! Is this simply not included in the spec, or am I missing some reason why this would not be safe?

EDIT: Gah, the idiom was new Base(other.foo) not new Base(other)


Sections 3.5.2 and 3.5.3 of the language specification spell this out, I'll post 3.5.2 for convenience (it's shorter!) and let you find 3.5.3 on your own.

In intuitive terms, when a type or member M is accessed, the following steps are evaluated to ensure that the access is permitted:

  • First, if M is declared within a type (as opposed to a compilation unit or a namespace), a compile-time error occurs if that type is not accessible.
  • Then, if M is public, the access is permitted.
  • Otherwise, if M is protected internal, the access is permitted if it occurs within the program in which M is declared, or if it occurs within a class derived from the class in which M is declared and takes place through the derived class type (§3.5.3).
  • Otherwise, if M is protected, the access is permitted if it occurs within the class in which M is declared, or if it occurs within a class derived from the class in which M is declared and takes place through the derived class type (§3.5.3).
  • Otherwise, if M is internal, the access is permitted if it occurs within the program in which M is declared.
  • Otherwise, if M is private, the access is permitted if it occurs within the type in which M is declared.
  • Otherwise, the type or member is inaccessible, and a compile-time error occurs.

Basically, access to protected members of the base have to be through instances of the derived. As you said, siblings cannot access each others' protected members, but the language specification also prohibits children from accessing protected members of the base unless the reference is through the child.


I you could do this, then you could always trivially invoke protected members of any class that allowed you to derive from it, even though the derived class is not used. This totally subverts the security of the protected mechanism.

For example, let's say we derive from Base with Derived as above. If the rules weren't as they are, you could add a method like this to Derived:

public static void CallProtectedMethod(Base baseInstance)
{
    baseInstance.ProtectedMethod();
}

and now anyone can invoke it like this:

Derived.CallProtectedMethod(baseInstance);

while the direct approach fails:

baseInstance.ProtectedMethod();

In this case baseInstance might really be of type Base and have nothing to do with Derived. To prevent this and ensure that protected methods stay protected unless the instance really is of the Derived type, calling these methods through a different instance is illegal.

Likewise for protected constructors:

public static Base CreateProtectedBase()
{
    return new Base();
}

and now anyone can invoke it like this:

var baseInstance = Derived.CreateProtectedBase();

while the direct approach fails:

var baseInstance = new Base();


its not accessible you can check this post for details : Many Questions: Protected Constructors


If you create a new object of base in derived you cannot access the protected members through that object. try this code

class Base
{
     protected int x;
}
class Derived : Base
{
    Base foo;
    void testMethod()
    {
        base.x = 5;
        foo.X = 5;// this throws an error 
    }
}

Change access specifier of the constructor to make it work or instead of creating a object of base class(Base) use base.X

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜