BuildQuill
C# learning path
24 of 25
Lesson 24 of 25
Lesson 24Beginner20 min

Organizing a C# Project

Move beyond one file: understand projects, namespaces, dependencies, configuration, and tests without creating architecture for its own sake.

Before this lesson

  • Classes and interfaces
  • Exceptions
  • Files
  • Async methods

Explain source files, projects, solutions, assemblies, and namespaces

Separate domain logic from console and storage concerns

Add dependencies and tests deliberately

The short answer

A .NET project file defines how source is built and which packages it uses. Organize code by cohesive responsibility, use namespaces to prevent naming collisions, keep configuration outside source, and add tests around rules that can fail.

01

Files help people navigate; projects define a build

C# does not require every class to live in a same-named file, but one focused public type per file is a useful convention. The .csproj project file tells the .NET SDK the target framework, compiler settings, package references, and which files form one build output called an assembly.

A solution can group several related projects, such as an application, a reusable domain library, and a test project. Do not split a small learning program into many assemblies immediately. Add a project boundary when independent deployment, dependencies, reuse, or test organization justify it.

02

Namespaces organize names, not files on disk

A namespace qualifies type names and avoids collisions: StudyTracker.Domain.Session differs from AnotherProduct.Session. Folder structure often mirrors namespaces because that helps navigation, but the compiler does not require the paths to match.

using imports a namespace for shorter references; it does not copy code or install a library. A package reference brings an external compiled dependency into the project. These are different operations even though both can lead to new type names becoming available.

ConceptPurposeTypical artifact
Source fileHuman navigation and declarationsStudySession.cs
NamespaceQualify and group type namesStudyTracker.Domain
ProjectOne build unit and dependency setStudyTracker.csproj
AssemblyCompiled outputStudyTracker.dll
SolutionGroup related projectsStudyTracker.sln
03

Separate policy from input, output, and storage

Console.ReadLine, file paths, and display colors are delivery details. The rule that a study session must have positive minutes is domain logic. Keeping rules in focused classes or methods lets a later web interface reuse them and lets tests call them without simulating a terminal.

A practical small structure might have Program coordinate the use case, Domain types enforce rules, and a file repository handle persistence. Do not create layers whose only work is passing the same values onward. Every boundary should make a dependency, policy, or ownership decision clearer.

C#
StudyTracker/
StudyTracker.csproj
Program.cs
Domain/
  StudySession.cs
  StudyLog.cs
Storage/
  FileStudySessionRepository.cs
Tests/
  StudyTracker.Tests.csproj
04

Packages, configuration, and tests are part of the program

NuGet packages provide reusable libraries. Add one only after checking ownership, maintenance, license, security posture, target-framework compatibility, and whether the standard library already solves the problem. Pin and review dependency updates rather than pasting package commands from old tutorials blindly.

Configuration that varies by environment—paths, service endpoints, feature settings—should not be hardcoded with secrets in source control. Tests should target decisions, calculations, and invariants. A method such as CalculateShipping is easier to test than a Main method that reads input and prints inside the calculation.

Good habits

  • Organize by coherent feature or responsibility, not a folder for every keyword.
  • Keep secrets out of source, logs, and committed settings files.
  • Review package transitive dependencies and current official guidance.
  • Write tests for boundaries and rules, not private implementation details.
  • Let architecture grow from demonstrated pressure.

Quick knowledge check

Answer before you reveal.

01Does adding a using directive install a NuGet package?

No. using shortens namespace references; package installation is a project dependency change.

02Must folders match namespaces?

No, but aligning them is a useful navigation convention in many projects.

Practice challenge

Now build it without copying.

Create a local .NET solution with a console project and a test project. Move a shipping calculation into a focused class, keep Console input in Program, and test totals below, at, and above the free-shipping boundary.

You are done when

  • dotnet build succeeds from the solution directory
  • The calculation project code has no Console calls
  • Tests cover normal and boundary cases
  • No secret or machine-specific absolute path is committed

Stretch: Add a storage interface and file implementation only after identifying which behavior a test double or second implementation would replace.

Open challenge in playground

Lesson checkpoint

One small step locks it in

Mark this lesson complete, then keep the momentum going.

Complete and continue

Clear up the details

Frequently asked questions

When should I create a class library project?

When code has a useful independent boundary, dependency set, reuse case, or test/deployment reason. One small console project can contain several well-organized files.

Which test framework should I use?

xUnit, NUnit, and MSTest are established choices. Follow current project or team conventions; the essential skill is designing testable code and meaningful cases.

What is dependency injection configuration?

It is the application startup code that chooses concrete implementations and supplies them to constructors. Framework containers can automate lifetime and resolution for larger apps.