Why I am able change this private field?

Quick Question: Why I am able to change his private field? My mind is stuck. It’s weird.

Here is an example code i wrote:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;



public class example : MonoBehaviour
{
    //Private fields
    private float thing;
    private int secret;




    //A public method for setting the private field "secret" for outsiders
    public void ChangeSecret(int newSecret)
    {
        secret = newSecret;
    }

    // A public method
    public void foo ()
    {

        example otherExample = new example();       //I just created another instance of example. I may have got it from code
                                                    //(like search for other example instances at the scene)
                                                    //It is just for demonstration purposes

        secret = 10;    //changing my own private field

        otherExample.secret = 5;    //!!How i can change his private field? Isn't it private??

        otherExample.ChangeSecret(5);   //This should be the only way I could change it, right?

    }

 
}

Interesting… feature (bug?): since your method where you create the example is inside the same class, so you technically still are in the same scope. In fact, if you just copy the content for foo() inside another class, the compiler will give you an error.

I don’t know if this is a bug or a feature, but it’s really interesting!

I did tried to do the same thing inside a script other than example and indeed the compiler said i dont have access. But when i am inside the script this happpens…

A class can always change it’s own variables, so I don’t know why you’re surprised here.

When declaring variables, you must also declare the accessibility level of the variable by putting private, protected or public. You may want any of those for a variety of reasons, such as simplifying your public API to the class - like, why would anyone want to see this? If it’s only relevant to internal processes then it should probably be private. If it’s a virtual class and will be overridden then maybe protected is necessary because the child class needs to see that internal value too. Or, if some user needs to access that variable directly to do something then it must be public.

1 Like

In C#, the private and protected accesibility modifiers, apply their restrictions per Type, not per instance.

There is no such thing as being able to “protect” read/write of variables in a per instance basis. They are just per Types. So any Type can modify a private value either for its own instance, or another instance of the same type,

PD: soz already answered above :stuck_out_tongue:

3 Likes

That is not accurate unless the class/variable is static. If the class is static, there would only be one instance so the point is moot.

MyClass can always say this.m_myPrivateVariable = 42 but it cannot say OtherInstanceOfMyClass.m_myPrivateVariable = 42 becuase it does not have proper scope to it.

That is not accurate unless the class/variable is static

This is legal c# code

public class Foo
{
    private float _someFloat;

    public void DoSomething(Foo otherFoo)
    {
        otherFoo._someFloat = 3;
    }
}

Furthermore, it is also allowed for derived types, as long as the field you are accessing was declared on the Type that is modifying it.


public class Bar : Foo { }
public class Foo
{
    private float _someFloat;

    public void DoSomething(Bar otherBar)
    {
        otherBar._someFloat = 3;
    }
}

I agree that exists a common pattern where static methods modify private instance fields of their own type, but is not restricted to static. Accesibility modifiers are applied per Type scope, not instance

1 Like

Wow! I actually had no idea it was by Type. I guess I just never really tried it because… why? Interesting to know this.

protected still restricts the access in its own functions. We can call the base functions of Foo to change something on Foo, but calling Bar.SomethingElse() would not allow access to Foo’s private variables - just protected even though it inherits.

1 Like

For protected is still legal as long as the type that modifies the variable belongs to the same inheritance chain. This means that Bar cannot modify a Foo protected field (because it doesnt know if it is also Bar) But it can modify that field it type is Bar or upper.

public class Foo
{
    protected float protectedAtFoo;
}
public class Baz : Bar { }
public class Bar : Foo
{
    
    public void DoSomething(Foo someFoo)
    {
        someFoo.protectedAtFoo = 3; // does not compile
    }
    public void DoSomething(Bar someBar)
    {
        someBar.protectedAtFoo = 3; // compiles
    }
    public void DoSomething(Baz someBaz)
    {
        someBaz.protectedAtFoo = 3; // compiles
    }
}
1 Like

The other one I find enormously helpful is being able to access private variables in static methods within the class. Whenever I need to do an AddComponent() and it needs a little bit of extra setup, I use this to keep the setup entirely local to the class file as well as to ensure I have 100% of what I need before making the thing… tidy! This is an example codelet:

And just for completeness I’ll mention the readonly attribute, which some folks swear by but isn’t super-helpful in Unity because Unity classes don’t let you write constructors, generally speaking, leaving you only declarations where you can set the value… which then is not really all that different from a const… so why not make it a const?

It’s also the case with nested type declarations. Nested types can access private members of their outer type:

public class SomeClass
{
	private string _someString;
	
	private NestedClass _nestedClass
	
	public NestedClass NestedClass => _nestedClass;
	
	public class NestedClass
	{
		private SomeClass _someClass;
		
		public NestedClass(SomeClass someClass)
		{
			_someClass = someClass;
		}
		
		public string GetString() => _someClass._someString; // accessing outer definition private member
	}
}

Terrible example, but it’s useful in a lot of cases.

1 Like

Ok thanks for the info guys! I didn’t know.

Irrelevant question: Does anyone know if this happens in C++?

Last time I used it (which was like, looks at watch, twenty years ago now O_o), it did.

1 Like

Const doesnt let you set the value from the constructor which is what you do when using DI, readonly keyword is very useful in vanilla c# in conjunction with dependency management