🎁 Give the #1 gift request of 2024... a ZTM membership gift card! 🎁

Beginner's Guide to To C# Access Modifiers (With Code Examples)

Claudio Bernasconi
Claudio Bernasconi
hero image

Have you ever wondered how to keep your C# code safe from accidental bugs or misuse? Access modifiers are your secret tools for writing secure and organized programs.

They give you full control over your program’s structure, protect sensitive data, simplify teamwork, and make your code easier to maintain. It’s like putting clear labels on your code—private for what’s yours, public for what’s shared!

In this guide, I’ll show you what access modifiers are, why they’re crucial, and how to use them with real examples. By the end, you’ll know exactly how to use them to write cleaner, more professional code.

Let’s dive in.

Sidenote: If you want to learn more about C#, then check out my C#/.NET Bootcamp course.

learn c sharp

This is the only course you need to learn C# programming and master the .NET platform. Plus, Claudio just recently added a massive new sections to teaching your how to build web applications with ASP.NET Core MVC, Razor Pages, and Blazor.

No previous coding experience required - you’ll learn C# programming from scratch, including powerful skills like data structures, object-oriented programming (OOP), and testing.

All while building your own projects, so you can get hired as a C#/.NET Developer in 2025!

Click the image or image above to check it out, or just start watching the first few lessons here for free (no signup or credit card needed, just start learning).

With that out of the way, let’s get into this 5-minute tutorial.

What are access modifiers in C#?

Access modifiers are like labels for your C# code. They let you decide what stays private and what can be shared, keeping your programs secure and easy to manage.

Why does this matter? It’s all about control.

Imagine trying to debug code where everything is accessible everywhere - it’s a nightmare. With access modifiers, you can enforce boundaries, protect sensitive data, and ensure your code is used exactly as intended.

For example

public class BankAccount
{
	private decimal balance; // Only accessible within this class.

	public void Deposit(decimal amount)
	{
    	balance += amount;
	}

	public decimal GetBalance()
	{
    	return balance;
	}
}

In this class, the balance field is marked as private, meaning it’s hidden from the outside world. You can only interact with it using the Deposit() and GetBalance() methods, which ensures balance updates happen in the way you’ve designed. This approach minimizes bugs and prevents accidental misuse of your code.

This mechanism is the C# implementation of the Encapsulation principle of Object-Oriented Programming (OOP).

Access modifiers also simplify teamwork. If you’re working with others, they help set boundaries, clarifying which parts of the code are safe to use and which are off-limits. Without them, you risk confusion, messy code, and time-consuming debugging.

Comparing C# to other languages

If you’ve worked with Java, Python, or JavaScript, you might be wondering how access modifiers in C# stack up. Let’s take a quick look:

  • Java: Java has similar access levels—public, private, and protected—but C# takes it further with protected internal and private protected for extra flexibility
  • Python: In Python, there’s no strict access control. Developers use naming conventions like _variable to signal private members, but C# enforces these rules at the language level, so nothing slips through by mistake
  • JavaScript: JavaScript only recently introduced access control, like #private fields. While helpful, it doesn’t offer advanced options like C#’s internal, which keeps things within your project

C# stands out because it gives you more tools to manage access. Whether you need fine-grained control or clear boundaries for your project, C# helps you write cleaner, safer code right out of the box.

Breaking down C# access modifiers

C# gives you six access modifiers to control how accessible your code is. Here’s a quick look at each one before we dive deeper:

Modifier Accessibility When to Use
public Accessible from anywhere. For methods or classes meant to be shared across your entire program or libraries.
private Accessible only within the same class. To encapsulate sensitive data or helper methods.
protected Accessible within the same class and derived (child) classes. To allow subclasses to reuse functionality while keeping it hidden from others.
internal Accessible only within the same assembly (project). To keep components reusable within your project without exposing them externally.
protected internal Accessible within the same assembly and from derived classes in other assemblies. For shared base classes that need to be inherited in other projects.
private protected Accessible within the same class and derived classes in the same assembly. For strict inheritance scenarios within the same project.

Now that you have the big picture, let’s break these down one by one with examples and common mistakes to avoid.

public: Open to everyone

The public modifier is the most open access level. Think of it as rolling out a red carpet—it lets any part of your program (or even external code) use the member you’ve marked as public.

This is great for creating reusable methods, classes, or libraries.

Why it’s useful 😎

Making a method or class public ensures it’s accessible wherever you need it. Whether you’re writing utility functions or building APIs, public makes your code easy to reuse and share.

Here’s a simple example—a utility class for formatting dates:

public class DateHelper
{
	public static string FormatDate(DateTime date)
	{
    	return date.ToString("yyyy-MM-dd");
	}
}

Because the FormatDate() method is public, it’s available to any part of your program:

string formattedDate = DateHelper.FormatDate(DateTime.Now);
// The method formats the date as "yyyy-MM-dd"

What to watch out for 🔭

It’s tempting to make everything public to avoid access issues, but this can lead to problems. For example, if a widely-used public method changes, it might break other parts of your program or any external code that depends on it.

Pro tip 🚀

Only use public for methods or classes you intend to share broadly. Ask yourself: Does this really need to be accessible everywhere? If not, consider a more restrictive modifier.

private: Keep it to yourself

The private modifier is your shield, hiding fields and methods from everything outside the class. It’s essential for protecting sensitive data and ensuring your code behaves exactly as you intend.

Why it’s useful 😎

When you make a field private, only the class that defines it can use it. This keeps sensitive data—like account balances—safe from external changes. By pairing private fields with carefully designed methods, you control how your data is accessed or modified, reducing the risk of bugs and misuse.

For example

Here’s a BankAccount class that uses a private field to protect an account balance:

public class BankAccount
{
	private decimal balance;

	public void Deposit(decimal amount)
	{
    	balance += amount;
	}

	public decimal GetBalance()
	{
    	return balance;
	}
}

With the balance field marked as private, other parts of your program can’t access it directly. Instead, they must use the Deposit() or GetBalance() methods, which ensures all updates follow your rules.

What to avoid 🙅‍♂️

Leaving internal data public can lead to major problems:

public decimal Balance; // Any code can modify this directly!

This exposes your data to the outside world, allowing other parts of your program—or even accidental changes—to bypass your logic and directly alter the balance.

Pro tip 🚀

Default to private for fields unless you’re certain they need to be accessed elsewhere. Controlled methods, like Deposit() or GetBalance(), let you enforce rules and protect your data from misuse.

protected: Sharing with family

The protected modifier lets you share members with subclasses while keeping them hidden from the rest of your program. It’s like letting family members access the guest room—not open to everyone, but available to those who need it.

Why it’s useful 😎

If you’re working with inheritance, protected gives child classes access to certain fields or methods without exposing them to the rest of your program. This balance between private and public is especially handy for sharing functionality across related classes.

For example

Here’s a base class for game characters, where Health is shared with subclasses like Warrior or Mage:

public class GameCharacter
{
	protected int Health = 100; // Accessible to subclasses.

	public void TakeDamage(int damage)
	{
    	Health -= damage;
	}
}

public class Warrior : GameCharacter
{
	public void DisplayHealth()
	{
    	Console.WriteLine($"Warrior's health: {Health}");
	}
}

In this example, Warrior inherits the Health field from GameCharacter. It can access and modify Health directly because it’s marked as protected.

What to avoid 🙅‍♂️

A common misunderstanding is assuming protected works like private for the base class. It doesn’t—any subclass can access and modify the member freely, which can lead to unintended behavior.

Pro tip 🚀

Only use protected when you’re confident that all subclasses will handle the member responsibly. If you need stricter control, consider using private protected instead.

internal: For the project only

The internal modifier is your project’s security guard. It keeps certain parts of your code accessible only within the same project or assembly, making it perfect for tools and logic that shouldn’t be exposed to the outside world.

Why it’s useful 😎

Think of internal as a way to keep your public API clean. By hiding project-specific components, you reduce clutter and ensure external code can’t misuse or depend on internal details.

This is especially important when working on libraries or larger applications.

For example

Here’s an example of an internal Logger class used for debugging:

internal class Logger
{
	internal static void Log(string message)
	{
    	Console.WriteLine($"[LOG]: {message}");
	}
}

Since this class and method are marked as internal, they can only be accessed from within the same project. External code won’t see or use them, keeping your debugging tools safely hidden.

What to avoid 🙅‍♂️

One common mistake is making project-specific classes public by default:

public class Logger
{
	public static void Log(string message)
	{
    	Console.WriteLine($"[LOG]: {message}");
	}
}

This exposes implementation details to external consumers, leading to unnecessary dependencies and potential misuse.

Pro tip 🚀

Always default to internal for project-specific components. Only make them public if you’re sure they need to be used by external projects or libraries.

protected internal: A wider family circle

The protected internal modifier is a unique combination of two access levels. It allows access to members from the same project and from subclasses in other projects. Think of it as opening your doors to trusted relatives, whether they’re nearby (within the same assembly) or visiting from far away (other assemblies).

Why it’s useful 😎

This modifier shines in library or framework development. It’s great for scenarios where you want to provide functionality for subclasses in other assemblies but keep it hidden from unrelated external code.

You might use protected internal for a base class with shared functionality that’s only meant for subclasses, whether they’re part of the library or extensions built by others.

For example

Here’s a Shape class in a drawing library:

public class Shape
{
	protected internal int Sides = 0; // Accessible to subclasses and same-project code.
}

public class Circle : Shape
{
	public Circle()
	{
    	Sides = 1; // Access is allowed because Circle is a subclass.
	}
}

In this example, Sides is accessible to the Circle subclass, even if it’s in a different project, as long as the library allows inheritance.

What to avoid 🙅‍♂️

A common mistake is overusing protected internal when simpler options like protected or internal would do the job. For example, if your code doesn’t need cross-assembly inheritance, protected alone might be enough.

Pro tip 🚀

Reserve protected internal for scenarios where both inheritance flexibility and cross-project access are truly needed. If either condition doesn’t apply, stick with a simpler modifier.

private protected: A stricter sibling

The private protected modifier is like a VIP pass for close family only. It keeps members accessible to the same class and its subclasses, but only within the same project. If you need tight control over access but still want to share functionality with derived classes, this is your go-to.

Why it’s useful 😎

private protected combines the best of private and protected, offering strict control while still allowing inheritance within your assembly. It’s perfect for scenarios where you trust subclasses in your project but want to keep things hidden from the outside world.

For example

Here’s how you might use private protected in a Device class:

public class Device
{
	private protected string SerialNumber = "SN12345"; // Accessible only within this class and its subclasses in the same project.
}

public class SmartDevice : Device
{
	public void DisplaySerialNumber()
	{
    	Console.WriteLine($"Serial Number: {SerialNumber}"); // Access allowed because SmartDevice is a subclass in the same project.
	}
}

In this example, SerialNumber is off-limits to external classes, but subclasses like SmartDevice can still use it within the same assembly.

What to avoid 🙅‍♂️

A common mistake is assuming private protected is stricter than it actually is. Subclasses within the same project still have full access, so it’s not as limited as private.

Pro tip 🚀

Use private protected when you need inheritance but want to avoid exposing members outside your project. If you don’t need inheritance, stick with private for maximum restriction.

Rule when no modifier is provided

What happens if we do not provide an access modifier to our code? It depends on the context. The following two rules are in place:

For members (fields, methods, etc.), the default is private. For types (classes, structs, etc.) at the namespace level, the default is internal.

Keep that in mind while writing your code. A common mistake is assuming that not using an access modifier will make all code public, which is not true.

It is generally best practice to explicitly set an access modifier for all class members (including fields and methods) and type definitions (classes, structs, etc.) to make the intention clear and to avoid any misunderstandings.

Wrapping it up: Your access control toolkit

Access modifiers aren’t just a feature - they’re your blueprint for writing secure, organized, and professional C# code.

By mastering them, you’re giving yourself the power to control who can use different parts of your program and ensure everything works exactly as you intended.

Whether you’re protecting sensitive data with private, making utility functions available with public, or balancing flexibility and control with protected or internal, these tools are here to help you write better, more reliable code.

Take a moment to review your projects. Are you using access modifiers intentionally?

If not, now’s the perfect time to refactor your code. The more you practice, the fewer bugs, security risks, and headaches you’ll face. You’re not just writing code—you’re future-proofing your skills.

Ready to take your coding to the next level? Dive into your next project and start putting these principles into action!

P.S.

Don’t forget - if you want to learn more about C# as well as the .NET platform, check out my complete course:

learn c sharp

No previous coding experience required - you’ll learn C# programming from scratch, including powerful skills like data structures, object-oriented programming (OOP), and testing. All while building your own projects, so you can get hired as a C#/.NET Developer in 2025!

It’s the only course you need to learn C# programming and master the .NET platform. You’ll learn everything from scratch and put your skills to the test with exercises, quizzes, and projects!

Plus, once you join, you'll have the opportunity to ask questions in our private Discord community from me, other students, and working developers.


There's always someone online 24/7 happy to help. It's by far the thing that my students always tell me is the best part of their experience. Hope you decide to take my course and if you do, make sure to come say hi on Discord!

Check it out above, or watch the first few videos here for free.

More Beginner 5-Minute C# Tutorials

If you enjoyed this post, check out my other C# tutorials:

More from Zero To Mastery

5 Reasons Why You Should Learn C# preview
5 Reasons Why You Should Learn C#

It's been 23 years since C# went live, but it's still growing in popularity. Find out why (+ why you should learn this language ASAP to advance your career).

Best Programming Languages To Learn In 2025 preview
Best Programming Languages To Learn In 2025

Want to know the best programming languages to learn in 2025? See the top 10 picks for high-paying jobs, future-proof skills, and unstoppable growth.

What Is C# Used For? Pretty Much Everything! preview
What Is C# Used For? Pretty Much Everything!

C# can build anything from Desktop + Web Apps to Cloud Integrations, Games, Automations + more. In this guide, I walk through why it works so well in each area.