C# Access Modifiers

In C#, access modifiers specify the accessibility of types (classes, interfaces, etc) and type members (fields, methods, etc). For example,

class Student {

  public string name;
    
  private int num;

  }

Here,

  • name - public field that can be accessed from anywhere
  • num - private field can only be accessed within the Student class

Types of Access Modifiers

In C#, there are 4 basic types of access modifiers.

  • public
  • private
  • protected
  • internal

1. public access modifier

When we declare a type or type member public, it can be accessed from anywhere. For example,

using System;

namespace MyApplication {

  class Student {
    public string name = "Sheeran";
      
    public void print() {
      Console.WriteLine("Hello from Student class");
     }
  }

  class Program {
    static void Main(string[] args) {
    
      // creating object of Student class
      Student student1 = new Student();
      
      // accessing name field and printing it
      Console.WriteLine("Name: " + student1.name);

      // accessing print method from Student
      student1.print();
      Console.ReadLine();
    }
  }
}

Output

Name: Sheeran
Hello from Student class

In the above example, we have created a class named Student with a field name and a method print().

// accessing name field and printing it
Console.WriteLine("Name: " + student1.name);

// accessing print method from Student
student1.print();

Since the field and method are public, we are able to access them from the Program class.

Note: We have used the object student1 of the Student class to access its members. To learn more, visit the C# class and objects.


2. private access modifier

When we declare a type member with the private access modifier, it can only be accessed within the same class or struct. For example,

using System;

namespace MyApplication {

  class Student {
    private string name = "Sheeran";
      
    private void print() {
      Console.WriteLine("Hello from Student class");
     }
  }

  class Program {
    static void Main(string[] args) {
    
      // creating object of Student class
      Student student1 = new Student();
      
      // accessing name field and printing it
      Console.WriteLine("Name: " + student1.name);

      // accessing print method from Student
      student1.print();

      Console.ReadLine();
    }
  }
}

In the above example, we have created a class named Student with a field name and a method print().

// accessing name field and printing it
Console.WriteLine("Name: " + student1.name);

// accessing print method from Student
student1.print();

Since the field and method are private, we are not able to access them from the Program class. Here, the code will generate the following error.

Error    CS0122    'Student.name' is inaccessible due to its protection level    
Error    CS0122    'Student.print()' is inaccessible due to its protection level    

3. protected access modifier

When we declare a type member as protected, it can only be accessed from the same class and its derived classes. For example,

using System;

namespace MyApplication {

  class Student {
    protected string name = "Sheeran";
  }

  class Program {
    static void Main(string[] args) {
    
      // creating object of student class
      Student student1 = new Student();
      
      // accessing name field and printing it
      Console.WriteLine("Name: " + student1.name);
      Console.ReadLine();
    }
  }
}

In the above example, we have created a class named Student with a field name. Since the field is protected, we are not able to access it from the Program class.

Here, the code will generate the following error.

Error    CS0122    'Student.name' is inaccessible due to its protection level    

Now, let's try to access the protected member from a derived class.

using System;

namespace MyApplication {

  class Student {
    protected string name = "Sheeran";
  }
  
  // derived class
  class Program : Student {
    static void Main(string[] args) {

      // creating object of derived class
      Program program = new Program();
      
      // accessing name field and printing it
      Console.WriteLine("Name: " + program.name);
      Console.ReadLine();
    }
  }
}

Output

Name: Sheeran

In the above example, we have created a class Student with a protected field name. Notice that we have inherited the Program class from the Student class.

// accessing name field and printing it
Console.WriteLine("Name: " + program.name);

Since the protected member can be accessed from derived classes, we are able to access name from the Program class.


4. internal access modifier

When we declare a type or type member as internal, it can be accessed only within the same assembly.

An assembly is a collection of types (classes, interfaces, etc) and resources (data). They are built to work together and form a logical unit of functionality.

That's why when we run an assembly all classes and interfaces inside the assembly run together. To learn more, visit the C# Assembly.


Example: internal within the same Assembly

using System;

namespace Assembly {

  class Student {
   internal string name = "Sheeran";
  }

  class Program {
    static void Main(string[] args) {
    
      // creating object of Student class
      Student theStudent = new Student();
      
      // accessing name field and printing it
      Console.WriteLine("Name: " + theStudent.name);
      Console.ReadLine();
    }
  }
}

Output

Name: Sheeran

In the above example, we have created a class named Student with a field name. Since the field is internal, we are able to access it from the Program class as they are in the same assembly.

If we use internal within a single assembly, it works just like the public access modifier.


Example: internal in different Assembly

Let's create one assembly first.

// Code on Assembly1
using System;

namespace Assembly1 {

  public class StudentName {
    internal string name = "Sheeran";
  }

  class Program {
    static void Main(string[] args) {
    }
  }
}

Here, this code is in Assembly1. We have created an internal field name inside the class StudentName. Now, this field can only be accessed from the same assembly Assembly1.

Now, let's create another assembly.

// Code on Assembly2
using System;

// access Assembly1
using Assembly1;

namespace Assembly2 {
  class Program {
    static void Main(string[] args) {
      StudentName student = new StudentName();

      // accessing name field from Assembly1
      Console.Write(student.name);
      Console.ReadLine();
     }
  }
}

Here, this code is in Assembly2. We are trying to access the name field of the StudentName class(Assembly1).

To access fields from Assembly1, we first need to set the reference of Assembly1 in Assembly2. Now the code

using Assembly1;

allows us to use the code from Assembly1 to Assembly2.

Here, when we try to access the name field from Assembly2, we get an error.

Error    CS0122    'StudentName.name' is inaccessible due to its protection level

This is because name is an internal field present in Assembly1.


5. protected internal access modifier

The protected internal is a combination of protected and internal access modifiers.

When we declare a member protected internal, it can be accessed from the same assembly and the derived class of the containing class from any other assembly.

// Code on Assembly1
using System;

namespace Assembly1 {
  public class Greet {
    protected internal string msg="Hello";
  }

  class Program {
    static void Main(string[] args) {
      Greet greet = new Greet();
      Console.WriteLine(greet.msg);
      Console.ReadLine();
     }
  }
}

Output

Hello

The above code is in Assembly1.

In the above example, we have created a class named Greet with a field msg. Since the field is protected internal, we are able to access it from the Program class as they are in the same assembly.

Let's derive a class from Greet in another assembly and try to access the protected internal field msg from it.

// Code on Assembly2
using System;

// access Assembly1
using Assembly1;

namespace Assembly2 {

  // derived class of Greet
  class Program: Greet {
    static void Main(string[] args) {
      Program greet = new Program();

      // accessing name field from Assembly1
      Console.Write(greet.msg);
      Console.ReadLine();
    }
  }
}

Output

Hello

The above code is in Assembly2.

In the above example, we have inherited the Program class from the Greet class(from Assembly1).

// accessing name field from Assembly1
Console.Write(greet.msg);

We are able to access the msg from the Greet class of Assembly1 from Assembly2.

This is because the msg is a protected internal field and we are trying to access it from the child class of Greet.


6. private protected access modifier

The private protected access modifier is a combination of private and protected. It is available from the C# version 7.2 and later.

When we declare a member private protected, it can only be accessed within the same class, and its derived class within the same assembly. For example,

// Code in Assembly1
using System;

namespace Assembly1 {
  public class StudentName {
    private protected string name = "Sheeran";
  }

  //derived class of StudentName class
  class Program1 : StudentName {

    static void Main(string[] args) {

      Program1 student = new Program1();

      //  accessing name field from base class
      Console.Write(student.name);
      Console.ReadLine();
    }
  }
}

Output

Sheeran

The above code is in Assembly1

In the above example, we have created a class StudentName with a private protected field name.

Notice that we have inherited the Program1 class from the StudentName class.

Since the private protected member can be accessed from derived classes within the same assembly, we are able to access name from the Program1 class.

Let's derive a class from StudentName in another assembly and try to access the private protected field name from it. For example,

// Code in Assembly2
using System;
//access Assembly1
using Assembly1;

namespace Assembly2 {

  //derived class of StudentName
  class Program : StudentName {
    static void Main(string[] args) {
      Program student = new Program();
    
      // accessing name field from Assembly1
      Console.Write(student.name);
      Console.ReadLine();
     }
  }
}

The above code is in Assembly2

In the above example, when we try to access the name field from the derived class of StudentName, we get an error.

Error    CS0122    'StudentName.name' is inaccessible due to its protection level    

This is because the name field is in Assembly1 and the derived class is in Assembly2.

Note: We can also use access modifiers with types (classes, interface, etc). However, we can only use types with public and internal access modifiers.

Did you find this article helpful?