Why and how does C# allow accessing private variables outside the class itself when it's within the same containing class?

I don't know if the question is descriptive enough but why and how does this behaviour exist?:

public class Layer
{
    public string Name { get; set; }

    private IEnumerable<Layer> children;
    public IEnumerable<Layer> Children
    {
        get { return this.children.Where ( c => c.Name != null ).Select ( c => c ); }
        set { this.children = value; }
    }

    public Layer ( )
    {
        this.children = new List<Layer> ( ); // Fine

        Layer layer = new Layer ( );
        layer.children = new List<Layer> ( ); // Isn't .children private from the outside?
    }
}

I can access layer.Children anywhere, that's fine, but how can I access layer.children since it's private?

Layer layer = new Layer ( );
layer.children = new List<Layer> ( );

only works if the code is inside the Layer class. Is there special code to treat accessing private variables differently if it's done inside the containing class, even though the access is from the outside?

I know the reason of using:

this.children = ...

inside the containing class, but creating new instances and modifying them from the outside, even if they are still within the containing class, doesn't seem like a good practice.

What's the reason for allowing this?


Solution 1:

See section 3.5.1 of the C# language specification. The relevant text is this:

Private, which is selected by including a private modifier in the member declaration. The intuitive meaning of private is “access limited to the containing type”.

Note that the modifier is relevant to the type, not the instance.

And then further in section 3.5.2 some rules are further explained:

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.

Solution 2:

This is a common design. It's assumed that whoever wrote the class knows how to work with it properly and understands what it means to directly access private members. So accessing private members of other instances of the same class often works. If you are familiar with C++'s friend construct, then it's like instances of the same class are all friends with each other (although C# has no friend notion officially).

This works in C# and Java, those are the two languages I know off the top of my head. I'll bet many other languages also allow this (anyone want to chime in?)

Solution 3:

Remember, private access modifier says Private members are accessible only within the body of the class or the struct in which they are declared. This description is confusing but it clearly says the restriction is at class level and NOT OBJECT LEVEL. In this case, layer is still within class.

This has been discussed here before. can we access a private variable using an object