A naming convention isn't decoration — it's a shared agreement that lets any C# developer read your code and immediately know what kind of thing they're looking at.
Look at these two lines side by side:
customer.Name
customer._name
An experienced C# developer glances at these and instantly knows something you didn't have to say out loud: the first is a public property — probably safe to read from anywhere. The second is a private field — internal state that shouldn't be touched from outside the class at all. Nobody explained that; the naming itself carried the information.
That's the entire point of naming conventions. .NET has a well-established, near-universal set of casing rules for types, methods, parameters, and fields. They're not arbitrary — every experienced C# developer already knows them, which means following them lets your code communicate instantly to anyone who reads it, and breaking them creates constant tiny friction ("wait, is this a field or a property?") for every person who touches your code afterward.
In this lesson, you'll learn the standard .NET naming conventions — PascalCase, camelCase, the underscore-prefix convention for private fields, and the I prefix for interfaces — and why consistency here matters more than personal preference.
A naming convention is an agreed-upon pattern for how to capitalize and format identifiers — the names you give to classes, methods, variables, and everything else in your code — so that the shape of a name tells you something about what it is, before you even read its meaning.
Microsoft's official .NET naming guidelines define two core casing styles and where each applies:
Two casing styles, applied consistently by role — that's essentially the whole system. The trick is knowing which role each identifier plays.
Imagine a codebase where every developer casing their own way: one person writes calculate_total(), another writes CalculateTotal(), a third writes calculateTotal() — all in the same file, all doing similar things. Now every time you read a name, you have to stop and mentally translate it, and you get zero information from the casing itself about whether it's a type, a method, or a local variable. Worse, inconsistency makes typos and mismatches far more likely — is it userName or userName (identical) or UserName (a different symbol entirely, since C# is case-sensitive)?
By agreeing on one convention per role — types and members get PascalCase, locals and parameters get camelCase, private fields get an underscore prefix — the .NET community turned casing into free information. The moment you see _total, you know it's a private field before you've even read what it holds. The moment you see IDisposable, you know it's an interface. This isn't enforced by the compiler (C# will happily compile code that ignores all of it) — it's a social convention, maintained because everyone benefits when everyone follows it.
A single class shows every convention working together at once:
public interface IPayable // I + PascalCase → interface
{
decimal CalculatePay(); // PascalCase → method
}
public class HourlyEmployee : IPayable // PascalCase → class
{
private readonly decimal _hourlyRate; // _camelCase → private field
public string Name { get; set; } = ""; // PascalCase → property
public decimal HoursWorked { get; set; } // PascalCase → property
public HourlyEmployee(string name, decimal hourlyRate) // parameters: camelCase
{
Name = name;
_hourlyRate = hourlyRate;
}
public decimal CalculatePay()
{
decimal grossPay = HoursWorked * _hourlyRate; // local variable: camelCase
return grossPay;
}
}
Reading this without any prior context: IPayable is unmistakably an interface, HourlyEmployee is unmistakably a type, _hourlyRate is unmistakably private state, and grossPay is unmistakably a throwaway local — all from casing alone.
Classes, records, structs, and enums are all capitalized at the start of every word: ExpenseTracker, OrderStatus, Point. This includes the file name too, by convention — ExpenseTracker.cs holds class ExpenseTracker.
I prefixpublic interface IComparable
public interface INotifyPropertyChanged
public interface IPayable
This is one of the few purely visual markers in the whole system, and .NET developers rely on it constantly — the instant you see a type starting with a capital I followed by another capital letter, you know it's a contract, not a concrete implementation.
public string FirstName { get; set; } // property
public void Deposit(decimal amount) // method
void Deposit(decimal amount) // parameter: camelCase
{
decimal newBalance = Balance + amount; // local variable: camelCase
Balance = newBalance;
}
public class BankAccount
{
private decimal _balance; // private field: _camelCase
private readonly string _accountId; // private readonly field: _camelCase
public decimal Balance => _balance; // exposed via a PascalCase property
}
This is arguably the single most valuable convention in the whole list, because it instantly disambiguates the extremely common pattern of a private field backing a public property with a nearly identical name — _balance vs Balance — without any risk of confusing the two.
public const int MaxRetryAttempts = 3;
public enum OrderStatus
{
Pending,
Shipped,
Delivered,
Cancelled
}
Note that this differs from some other languages (like C or older C++ style guides), which often use ALL_CAPS for constants — that convention doesn't apply in idiomatic C#.
Here's the same tiny class written first with inconsistent, ad-hoc casing, then following the standard convention:
// Before — inconsistent, no visual cues
public class person
{
public string name;
public int Age;
public string get_greeting() { return "Hi, " + name; }
}
// After — follows convention, self-explanatory
public class Person
{
private string _name;
public string Name { get; set; }
public int Age { get; set; }
public string GetGreeting() => $"Hi, {Name}";
}
Notice how, in the "after" version, you can tell at a glance which members are public API (Name, Age, GetGreeting) versus private internal state (_name) — purely from casing, without reading a single access modifier.
In a team setting, naming conventions are usually enforced automatically through an .editorconfig file checked into the repository, which most IDEs read and flag violations against in real time:
# .editorconfig (excerpt)
dotnet_naming_rule.private_fields_underscore_camel.severity = warning
dotnet_naming_rule.private_fields_underscore_camel.symbols = private_fields
dotnet_naming_rule.private_fields_underscore_camel.style = underscore_camel_case
dotnet_naming_rule.interfaces_prefix_i.severity = warning
dotnet_naming_rule.interfaces_prefix_i.symbols = interfaces
dotnet_naming_rule.interfaces_prefix_i.style = pascal_case_i_prefix
When a developer opens a pull request that names a private field hourlyRate instead of _hourlyRate, the IDE underlines it and the build can even fail in CI. This isn't bureaucracy for its own sake — it's what lets a team of developers who've never met read each other's code without a single conversation about "how do you name things here?"
A red octagon always means "stop," everywhere, without needing to read the word. A dashed yellow line always means "you may pass here"; a solid one means "you may not." Drivers don't relearn these rules at every intersection — the shape and color already carry the meaning, universally.
Naming conventions do the same job for code. IPayable is a red octagon that says "interface" before you've read another word. _hourlyRate is a solid line that says "private, don't touch from outside." You're not memorizing a new rule for every codebase you join — the convention already told you.
Both capitalize the first letter of every word except the first. camelCase keeps that very first letter lowercase (orderTotal); PascalCase capitalizes it too (OrderTotal). Everything else is identical.
No — it's purely convention, not a language rule. private decimal balance; compiles just as fine as private decimal _balance;. The prefix exists purely to help human readers, and its value comes entirely from everyone agreeing to use it.
Older code (especially from the pre-.NET Windows/COM era) sometimes prefixes variables with a type hint, like strName or iCount. Modern C# strongly discourages this — the compiler's static typing already tells you the type, and IDEs show it on hover, so encoding it into the name just adds noise (and gets wrong the moment the type changes but nobody updates the name).
One class uses _name for private fields, another uses m_name, a third uses plain name. Every reader has to relearn the rules per file.
Pick the standard .NET convention and apply it uniformly — ideally enforced by an .editorconfig so it isn't left to memory.
string strFirstName;, int iTotalCount; — encodes type information the compiler and IDE already give you for free.
Just name it for what it represents: firstName, totalCount.
I prefix on interfaces interface Payable { ... } — looks identical to a class name, and readers have to open the declaration to find out it's actually a contract.
interface IPayable { ... } — unmistakable at a glance.
decimal amt; string custNm; — saves a few keystrokes at the cost of forcing every future reader to decode an abbreviation.
Reserve single letters for genuinely tight, obvious scopes (for (int i = 0; ...)). Everywhere else, spell it out: amount, customerName.
.editorconfig with different rules than described here, follow the team's rules — the goal is consistency within a codebase, not rigid adherence to any single external guideline._balance).I prefix on top of PascalCase (IPayable)..editorconfig, that makes reading unfamiliar C# code dramatically faster for everyone.You've learned the standard .NET casing rules for every kind of identifier. Let's check they'll stick when you're writing real code.
1. Which of these correctly follows standard .NET naming conventions for a private field and its backing property?
Correct: B
Why B is correct: The private field uses the underscore-prefixed camelCase convention (_balance), and the public property uses PascalCase (Balance) — exactly matching the standard .NET pattern for a field-backed property.
Why A is incorrect: The casing is reversed — the private field is capitalized like a public member, and the public property is lowercase like a local.
Why C is incorrect: The private field is missing its underscore prefix, making it visually indistinguishable from a local variable.
Why D is incorrect: m_Balance is a Hungarian-notation-style prefix from older non-.NET conventions, not the idiomatic .NET underscore style, and the public property is incorrectly lowercase.
Reinforcement: Private fields get _camelCase; public properties get PascalCase — this pairing is one of the most common patterns you'll write.
2. Which name correctly follows convention for a new interface describing something that can be validated?
Correct: C
Why C is correct: Interfaces in .NET use PascalCase with a leading capital I, which is exactly what IValidatable does.
Why A is incorrect: This is valid PascalCase, but without the I prefix it looks identical to a class name, losing the instant "this is an interface" signal.
Why B is incorrect: Lowercase-first casing (camelCase) is reserved for locals and parameters, never for type names like interfaces.
Why D is incorrect: Spelling out "Interface" in the name is redundant and not the .NET convention — the I prefix already communicates that.
Reinforcement: Interfaces always combine PascalCase with a leading I.
3. Inside a method body, which of these is the correctly-cased local variable declaration?
Correct: C
Why C is correct: Local variables use camelCase — the first word lowercase, subsequent words capitalized — exactly as in totalPrice.
Why A is incorrect: PascalCase is reserved for types and public members, not local variables.
Why B is incorrect: The underscore prefix is reserved for private fields at the class level, not local variables declared inside a method body.
Why D is incorrect: Snake_case (words separated by underscores) is not the standard C# convention for any identifier category.
Reinforcement: Locals and parameters both use camelCase, with no underscore prefix.
4. Why does the .NET naming convention specifically distinguish private fields (_balance) from public properties (Balance) with different casing, rather than letting them look the same?
Correct: B
Why B is correct: This distinction resolves a very common naming collision — a private field and its public property often represent "the same" piece of data — while letting the reader instantly tell which one is safe to use from outside the class and which is internal implementation detail.
Why A is incorrect: C# would compile balance and Balance as distinct symbols regardless (C# is case-sensitive); the compiler has no such restriction.
Why C is incorrect: There's no length rule involved — the underscore is a fixed prefix, not a length constraint.
Why D is incorrect: The convention exists specifically to give readers a fast, reliable visual signal about scope and intent — that's a concrete, practical benefit, not an arbitrary rule.
Reinforcement: Consistent, role-based casing turns a name's shape into free information about what it represents.
You now read and write C# names the way the rest of the .NET community does — one less thing to think about, every single time you open a file.
dotnetmadeeasy.com — Learn C# and .NET, the right way.