A sign post with the word "Private"

Understanding the 4 Access Modifiers in C#

Do you know them? What would you use one over another? Let’s look at it in detail.

In C#, accessors define the visibility and accessibility of members (fields, properties, methods, etc.) within a class or struct. The main accessors in C# are private, public, and protected. Here’s a detailed explanation of each.

What Are The Accessors

Private Accessor

The members declared with the privateaccessor are accessible only within the same class or struct.

You can use privateto encapsulate data and restrict its access from outside the class. It helps to maintain control over the data and ensures that you can’t modify or access it directly from other parts of the code.

In the example below, the namefield is private and can only be accessed or modified through the SetNameand GetNamemethods.

The convention is also to prefix the field with _.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Person
{
    private string _name;

    public void SetName(string name)
    {
        this._name = name;
    }

    public string GetName()
    {
        return this._name;
    }
}

Public Accessor

The members declared with the publicaccessor are accessible from any other code. There are no restrictions on their accessibility.

You use publicwhen you want to expose members to be accessible from outside the class or struct, such as in a library or API where you need to provide access to certain functionality.

In the example below, the Nameproperty is public and can be accessed and modified directly from outside the Personclass.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
namespace Some.Library;

public class Person
{
    public string Name { get; set; }
    public Person() {}
}

using Some.Library;
namespace Some.Project.Using.The.Library;
class Polite {
    void Greet()
    {
        var person = new Person()
        person.Name = "Jeremie";
        Console.WriteLine($"Hello, my name is {person.Name}.");
    }
}

Protected Accessor

The members declared with the protectedaccessor are accessible within the same class or struct, and in derived classes (subclasses).

You use protectedwhen you want to allow access to members in the base class and any derived classes but restrict access from other parts of the code.

In the example below, the speciesfield is protected and can be accessed in the Animalclass and the Dogclass, which is derived from Animal.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Animal
{
    protected string species;

    public void SetSpecies(string species)
    {
        this.species = species;
    }
}

class Dog : Animal
{
    public void DisplaySpecies()
    {
        Console.WriteLine($"This dog belongs to the species: {species}");
    }
}

Additional Access Modifiers

C# also provides other access modifiers like internaland protected internal:

internal makes members accessible within the same assembly, but not from another assembly.

1
2
3
4
internal class InternalClass
{
    internal int InternalProperty { get; set; }
}

protected internal makes members accessible within the same assembly and a related class in the assembly.

1
2
3
4
protected internal class ProtectedInternalClass
{
    protected internal int ProtectedInternalProperty { get; set; }
}

What about the implicit access modifiers in the class

You may wonder in the examples above what happens when you don’t specify the access identifier on the class, method or property.

The access modifier of a class itself is important and can affect how the class is accessed. In C#, if a class doesn’t specify an explicit access modifier, it defaults to internal.

Important Notes

  • For Top-Level Classes: In C#, top-level classes (i.e., those that aren’t nested within another class) can only have publicor internalaccess modifiers. They can’t be privateor protected.
  • For Nested Classes: When a class is nested within another class, it can have any access modifier (public, private, protected, internal, protected internal).

Example with Nested Classes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class OuterClass
{
    private class InnerPrivateClass
    {
        // Accessible only within OuterClass
    }

    protected class InnerProtectedClass
    {
        // Accessible within OuterClass and derived classes
    }

    internal class InnerInternalClass
    {
        // Accessible within the same assembly
    }

    public class InnerPublicClass
    {
        // Accessible from any other assembly
    }
}

In this example:

  • InnerPrivateClassis accessible only within OuterClass.
  • InnerProtectedClassis accessible within OuterClassand derived classes.
  • InnerInternalClassis accessible within the same assembly.
  • InnerPublicClassis accessible from any assembly.

Conclusion

Understanding and using class access modifiers correctly helps in designing your code’s architecture, controlling access levels, and ensuring proper encapsulation and security.

Follow me

Thanks for reading this article. Make sure to follow me on X, subscribe to my Substack publication and bookmark my blog to read more in the future.

Photo by Tim Mossholder

Licensed under CC BY-NC-SA 4.0
License GPLv3 | Terms
Built with Hugo
Theme Stack designed by Jimmy