Question
C# Access Modifiers and static: public, private, protected, and Defaults
Question
In C#, what are the differences between the public, private, and protected access modifiers, and what happens when no access modifier is written?
I have mostly used public throughout college and want to understand when each access level should be used. Also, how does the static keyword differ from leaving it off a member?
Short Answer
You will learn how C# access modifiers control who can use a type or member, what default accessibility means, and why static is a separate concept from accessibility. You will also see when to use instance members versus class-level static members.
Concept
Access modifiers define accessibility: the parts of a program that are allowed to use a type, field, method, property, or constructor.
publicmeans accessible from any code that can access the containing type or assembly.privatemeans accessible only inside the type that declares it.protectedmeans accessible inside the declaring type and inside types derived from it.- Omitting an access modifier uses a C# default that depends on where the declaration appears.
For members declared directly in a class or struct, the default is private:
class Account
{
string ownerName; // private by default
}
For a top-level type declared directly in a namespace, the default is internal, meaning it is available anywhere in the same assembly (usually the same project output), but not from another assembly:
class ReportGenerator // internal by default
{
}
static is not an access modifier. It answers a different question:
- Access modifiers answer: Who may use this?
staticanswers:
Mental Model
Think of a class as an apartment building.
publicis the building lobby: anyone allowed into the building can use it.privateis an apartment's locked safe: only that apartment can access it.protectedis a private family space: the apartment itself and apartments belonging to its inherited family can access it.- No modifier means C# applies the building's default rule for that location.
Now think of static as the difference between a shared building noticeboard and each apartment's own mailbox:
- A
staticfield is the one shared noticeboard for the entire building. - An instance field is a separate mailbox for every apartment.
Accessibility and static can be combined. For example, a field can be private static: private to the class but shared by every instance.
Syntax and Examples
A class can expose a small public API while keeping implementation details private.
public class BankAccount
{
private decimal balance;
public string Owner { get; }
public BankAccount(string owner, decimal openingBalance)
{
Owner = owner;
balance = openingBalance;
}
public void Deposit(decimal amount)
{
if (amount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(amount));
}
balance += amount;
}
public decimal GetBalance()
{
return balance;
}
}
BankAccount is public, so another project can use the type if it references the assembly. Deposit and GetBalance are public because they are intended operations for callers. balance is private, so callers cannot directly set it to an invalid value.
Step by Step Execution
Consider this code:
public class ScoreTracker
{
private int score;
public static int CreatedCount { get; private set; }
public ScoreTracker()
{
CreatedCount++;
}
public void AddPoints(int points)
{
score += points;
}
public int GetScore()
{
return score;
}
}
var playerOne = new ScoreTracker();
playerOne.AddPoints(10);
var playerTwo = new ScoreTracker();
playerTwo.AddPoints(5);
Console.WriteLine(playerOne.GetScore()); // 10
Console.WriteLine(playerTwo.GetScore()); // 5
Console.WriteLine(ScoreTracker.CreatedCount); // 2
Execution trace:
playerOneis created. Its instance fieldscorestarts at .
Real World Use Cases
- Public API methods: A service exposes
public Task<User> GetUserAsync(...)so controllers and other consumers can request user data. - Private implementation details: A class stores a private database connection helper or calculation method so callers cannot depend on internal implementation choices.
- Protected extension points: A framework base class gives derived classes a protected method such as
ValidateRequest()or a protected property needed to customize behavior. - Internal application code: In a multi-project solution,
internaltypes can be shared inside one assembly without becoming part of a library's public API. - Static utility methods:
Math.Sqrt,string.IsNullOrWhiteSpace, and helper classes often use static methods when no object-specific state is needed. - Static shared state: Application-wide configuration, cached read-only data, counters, or a singleton-like shared resource may be static. Shared mutable state should be used carefully because it can make tests and concurrent code harder to manage.
Real Codebase Usage
Developers usually keep fields private and provide intentional public methods or properties. This protects class invariants: rules that must always remain true.
A common validation pattern is to expose a public method while keeping mutation private:
public class UserProfile
{
public string DisplayName { get; private set; }
public UserProfile(string displayName)
{
DisplayName = ValidateName(displayName);
}
public void ChangeDisplayName(string newName)
{
DisplayName = ValidateName(newName);
}
private static string ValidateName(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("A display name is required.", nameof(value));
}
return value.Trim();
}
}
Here:
Common Mistakes
Making every field public
This allows callers to put an object into an invalid state.
public class Temperature
{
public double Celsius;
}
var temperature = new Temperature();
temperature.Celsius = -1000; // Possibly invalid for the application's rules.
Prefer private fields and validate updates through a method or property.
public class Temperature
{
private double celsius;
public double Celsius
{
get => celsius;
set
{
if (value < -273.15)
{
throw new ArgumentOutOfRangeException(nameof(value));
}
celsius = value;
}
}
}
Assuming no modifier always means private
It depends on the declaration location.
{
{
}
}
Comparisons
| Feature | What it controls | Who can access or use it | Typical use |
|---|---|---|---|
public | Accessibility | Any permitted caller | A type's intended API |
private | Accessibility | Only the declaring type | Fields and internal helper methods |
protected | Accessibility | Declaring type and derived types | Carefully designed inheritance hooks |
internal | Accessibility | Code in the same assembly | Project or library implementation types |
| No modifier on class member | Default accessibility | Private for class/struct members |
Cheat Sheet
public class Product // Available to other assemblies
{
private decimal price; // Only this Product class
protected string Code { get; set; } // Product and derived classes
public string Name { get; } // Callers can read it
internal void Refresh() { } // Same assembly only
public static int Count { get; private set; } // One value for Product
public void ApplyDiscount(decimal percent) { } // Called on a Product object
}
- Use
publicfor a deliberate API. - Use
privateby default for fields and implementation helpers. - Use
protectedonly when derived classes need an intentional extension point.
FAQ
What is the default access modifier for a C# class?
A top-level class declared in a namespace defaults to internal. A nested class defaults to private.
What is the default access modifier for C# methods and fields?
Methods, fields, properties, and constructors declared directly in a class or struct default to private when no modifier is written.
Should I use public or private by default in C#?
Use the least access necessary. Fields are normally private. Make a member public only when other code truly needs it as part of the class's intended API.
Can code outside a class access a protected member?
No. A protected member is accessible within the declaring class and from derived classes, subject to C#'s inheritance access rules.
Is static an access modifier in C#?
No. static controls whether a member belongs to the type or to each object instance. It is independent of public, private, and protected.
When should a C# method be static?
Make it static when it does not need instance fields, instance properties, or other instance behavior. Utility and validation methods are common examples.
Can a static member be private or public?
Yes. For example, private static int counter; is shared within the class, while can be accessed through the type.
Mini Project
Description
Build a small library tracker that keeps each book's availability as instance state while also keeping a shared count of all books created. The project demonstrates private fields, public behavior, a protected extension point, and a static shared value.
Goal
Create book objects that can be borrowed safely and report the total number of books created.
Requirements
- Create a public
LibraryBookclass with a title supplied by its constructor. - Keep the borrowed status inaccessible for direct changes from outside the class.
- Provide public methods to borrow and return a book.
- Track the total number of created books with a static public read-only property.
- Create a derived
ReferenceBookclass that uses protected behavior to prevent borrowing. - Demonstrate the behavior by creating and using both book types.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Array Initialization Syntaxes Explained
Learn all common C# array initialization syntaxes with examples, rules, comparisons, and mistakes beginners often make.