Home / Software Development / C# Explained Simply
Programming Languages

C# Explained Simply

A missing price and a price of zero can look identical on a screen. Why must a C# program tell them apart?

C# is a general-purpose programming language widely used for web applications, APIs, business systems, cloud services, desktop tools and games. Its type system and .NET libraries help developers express rules clearly and reuse tested capabilities. This guide follows a C# request from controller to service and database, explains compilation and error handling, and shows why maintainable structure matters more than merely making code build.

7 min read
C# Explained Simply — original ExplainItSimply topic illustration

By

Zero is a supplied numeric value; missing means the value has not been provided. Treating both as zero can accidentally make an unknown price look like a free stay.

A nullable decimal can represent absence. Check for a supplied rate before multiplying, then apply an explicit rule for whether a deliberate zero is allowed.

An empty price field must not turn into a free holiday

A room costs R750.50 per night and a guest wants three nights. Multiplying gives R2,251.50, but a useful program must also decide what to do when the price is missing, negative or deliberately zero. Those are different situations, even if an untidy screen makes them look similar.

This guide is for a reader who wants to understand the decisions behind an application. You do not need to have written C# before. We will follow a small pricing rule, predict its result, and then connect that rule to a real server. By the end, you should be able to explain why a program needs both suitable types and explicit checks.

Why should a blank price not silently become zero?

A number alone cannot always describe a business state.

Trace the explanation

A nullable decimal can distinguish no price supplied from an explicitly permitted zero price. The server must validate that distinction before calculating money, even if the browser already checked the form.

Source and further reading: Microsoft Learn

A missing price should not silently become a free room

A numeric value and an absent value represent different states. If a price field has not been supplied, converting it to zero can create a misleading business result. C# offers types and nullable values that help represent those distinctions, but the developer still has to choose the correct meaning.

For money, decimal is commonly used to represent decimal quantities more suitably than binary floating-point. That does not decide the rounding policy. You must still specify when to round, to how many places and how taxes or adjustments are applied.

Rate 750.50; nights 3 to Return 2251.50; absent rate is rejected1: Rate 750.50; nights 3. 2: Check supplied, non-negative, positive. 3: Return 2251.50; absent rate is rejected.1Rate 750.50; nights 32Check supplied, non-negative,positive3Return 2251.50; absent rate isrejected

Read one pricing method as a sequence of decisions

Our teaching rule accepts a supplied, non-negative nightly rate and a positive whole number of nights. A supplied zero is allowed here to represent a complimentary stay; a real business can choose a different policy. Missing information is rejected rather than silently converted to zero.

public static decimal CalculateStay(decimal? nightlyRate, int nights)
{
    if (!nightlyRate.HasValue)
        throw new ArgumentException("Supply a nightly rate.", nameof(nightlyRate));

    if (nightlyRate.Value < 0m || nights < 1)
        throw new ArgumentException("Rate must be non-negative and nights must be positive.");

    return nightlyRate.Value * nights;
}

In the example, decimal? means the rate may contain a decimal value or be absent. HasValue asks whether it was supplied; Value retrieves it after that check. The m suffix marks a C# decimal literal. The two parameter types describe the values, while the if statements describe the rules.

Trace R750.50 and three nights: the rate exists, it is not negative, and the night count is positive, so the method returns 750.50 × 3. With no rate, the first guard stops the method before multiplication. An exception signals that this method's contract was not met; a web application would normally translate appropriate validation failures into a useful response rather than show a raw stack trace.

This small method excludes taxes, discounts, currency conversion and rounding rules. It is not a complete reservation price engine. That boundary matters: a correct multiplication does not prove the total includes every charge.

Read one pricing method as a sequence of decisions — worked evidence
Nightly rateNightsExpected outcome
R750.503R2,251.50
Not supplied3Reject before multiplying
R0, explicitly supplied3R0 under this teaching policy
R750.500Reject the invalid night count

Change the stay to four nights at R750.50. What total should the method return, in rand?

This checks a prediction about the worked example. It does not run server code, contact an API or change a booking.

Read the explanation without the checker

R3,002.00: the guards pass and 750.50 × 4 = 3,002. Missing is not zero; a deliberately supplied zero follows the stated policy.

Now inspect the passing-mark method retained below. Explain why 101 is rejected before the pass comparison. This transfers the same guard-before-calculation idea to a different problem.

Practical examples: C#

Booking

A booking API written in C# can validate dates, check permissions, calculate charges and reserve availability inside a controlled transaction. The browser requests an action; trusted server code decides whether that action is allowed and returns a clear result.

Payment

Payment code can use strongly typed models to separate amounts, references and provider responses. Exceptions and logs capture technical failure, while business outcomes such as “declined” remain controlled results instead of being confused with system crashes.

Insurance

An insurance service may combine customer details, cover rules, risk factors and effective dates. C# classes can represent those concepts explicitly, while tests check boundaries such as expired policies, exclusions and missing information.

Business

Internal business systems often run long-lived workflows instead of one isolated calculation. Background services, scheduled jobs and APIs written in C# can coordinate invoices, notifications and reports while sharing the same validation and data-access rules.

Further context: Read one pricing method as a sequence of decisions

The practical takeaway

This is why C# is common in business software: the language is less about flashy syntax and more about maintaining rules safely over years of change. Features such as classes, interfaces, exceptions, asynchronous programming and compile-time type checking help teams organise large codebases and catch many mistakes before software reaches users.

One misconception to clear up

C# is sometimes described as a Windows-only language. That was a reasonable historical association, but modern .NET is cross-platform. C# applications can run on Windows, Linux, containers and cloud platforms. What matters is the .NET runtime and the libraries the application uses, not the operating system on the developer’s laptop.

A room costs R750.50 per night. What is the subtotal for 4 nights, excluding extras?

Trace the explanation

750.50 × 4 = R3002.00. Use decimal arithmetic for this example. A valid subtotal still requires explicit rules for missing prices, invalid nights and any separately calculated charges.

Worked relationship: 750.50 × 4 = R3002.00. 750.50: nightly rate; 4: valid nights; 3002.00: subtotal

Source and further reading: Microsoft Learn

Why can the right number type still produce the wrong bill?

A decimal type helps represent decimal quantities, but it does not choose a tax rule, discount order or rounding policy. Those decisions remain business logic.

Rounding each line and rounding only the final total can differ. Write down the required policy and test a case where the alternatives produce different answers.

What happens after the code compiles

Before a C# application runs, the project is compiled into .NET assemblies. At runtime, the .NET runtime loads those assemblies, manages memory and turns intermediate instructions into machine code for the computer that is actually executing the application. That layer is why the same C# project can be deployed to different supported environments without a developer manually rewriting the business rules for each processor. In a web service, the runtime also works with the ASP.NET hosting pipeline so requests can be routed to the correct controller or endpoint, dependency-injected services can be created, and asynchronous work can release threads while the application waits for databases or external services.

For a business system, the bigger design question is where each rule belongs. A rule that says only a confirmed booking can be checked in should normally live in server-side business logic, not only in an Angular button. The screen can guide the user, but C# on the server should still reject an invalid request. Keeping that boundary clear protects the system when another client, scheduled process or future mobile app uses the same API.

Why the server repeats checks the browser already made

A browser may prevent an empty booking date, but a caller can bypass that page and send a request directly. Server-side code therefore checks required values, permissions and allowed transitions before changing data. Client validation improves the experience; it is not an access-control boundary.

A service method should also return an outcome the caller can interpret: accepted, invalid input, unavailable or failed unexpectedly. Returning only 'true' hides distinctions the interface needs. Clear types, explicit states and careful error handling turn business rules into a contract another developer can use.

Can a typed language prevent every incorrect business calculation?

No. A value can have the right type and the wrong unit, date range or business meaning. Types help express constraints, while examples and validation establish the intended behaviour.

Trace C# from web request to stored result

Start with the API contract that receives the request, then see how authentication and authorisation establish the caller’s identity and permissions. C# services frequently finish the workflow by executing controlled SQL operations and returning a structured JSON response.

Questions about C# Explained Simply

Is C# good for beginners?

Yes, especially if you want to build business systems, APIs or enterprise applications.

Is C# only for Windows?

No. Modern .NET can run on Windows, Linux and cloud platforms. Cross-platform deployment depends on the runtime, workload and libraries used. Windows-specific APIs and desktop frameworks do not become portable merely because the code is C#.

Does C# replace JavaScript?

No. They often solve different parts of the same system. JavaScript or TypeScript commonly runs in the browser, while C# can run on the server and enforce business rules, security and data access.

Why does C# use types such as int, string and DateTime?

Types tell the compiler what kind of value a variable is meant to hold. That makes code easier to reason about and allows many mistakes to be caught before the program is run.

What is .NET in relation to C#?

.NET is the platform and runtime around the language. C# is one of the languages used to write .NET applications; the runtime supplies memory management, libraries, networking, file access and many other services.

Where would a beginner start?

Start with variables, conditions, loops and methods, then build a very small console or web API project. The important step is to connect each language feature to a problem the program is actually solving.

A customer changes the nightly rate in browser developer tools. Where should the trusted price come from?

One reasoned response

The server should load the authorised rate and enforce the booking rules. A submitted field is input, not proof of entitlement. The interface can help users avoid mistakes but cannot be the authority on price.

Source and further reading: Microsoft Learn

Example: validate a value before using it

C# is a strongly typed language commonly used for .NET applications. A method can make a rule explicit and reusable.

public static bool IsPassingMark(int mark)
{
    if (mark < 0 || mark > 100)
    {
        throw new ArgumentOutOfRangeException(nameof(mark));
    }

    return mark >= 50;
}

The method rejects values outside the expected mark range and then checks the pass threshold. Whether invalid input should throw an exception or return a validation result depends on the application's contract. The important part is to define that behaviour deliberately. In a web application, validate input at the boundary, apply server-side checks even if the browser also validates, and return errors that help the user without exposing sensitive implementation details.

Sources

Sources and further reading

A closer look

Missing is different from zero

A request carries an optional discount. A nullable decimal can distinguish no discount supplied from an explicit 0.00. That distinction may decide whether to apply a default.

Work through the distinction

Validate at the boundary, then use decimal arithmetic for monetary examples and an explicit rounding rule where required. A type helps represent meaning, but it does not decide whether a discount is allowed for that member.

Does an explicit zero necessarily mean missing?

Choose an answer to see feedback. You can try again.

Show the answer and explanation

No, it can be a supplied value. Validate at the boundary, then use decimal arithmetic for monetary examples and an explicit rounding rule where required. A type helps represent meaning, but it does not decide whether a discount is allowed for that member.

Help us make learning clearer

Was this explanation useful?

Your rating helps us understand which explanations are working and where we can improve.

—/ 5·0 ratings
Community

Join the conversation

Add your perspective, ask a useful question or share what stood out.

0 comments
◌ No comments yet

This conversation is waiting for its first useful thought.