What is the difference between a class and an object, and what types of constructors does C# have?
16 reports in the index, from Infosys, Capgemini, Zobi, Sdaemon, Ishttaa and others; constructor types and the static-versus-default order repeat most.
Say this first · about 30 seconds
A class is a type, written once. An object is one instance (one filled-in copy) made from it at run time, with its own copy of the data.
An instance constructor has the class name and no return type; it runs for every new object and leaves it valid.
Types: parameterless, the default constructor that C# adds only when you write no instance constructor; parameterized and overloaded (several constructors with different parameters); static; and private. A copy constructor is one you write.
A static constructor runs once per type, before the first object or static member (a field or method marked static, shared by the type) of that class is used, and cannot be called by name. So it runs before the parameterless instance constructor, always, except when a static field initializer (a value written on the field itself) creates the class itself.
Then for each object: instance field initializers, then the constructor body. With a parent class (the base class it inherits from), the parent's constructor runs after the child's field initializers.
Chaining: a constructor can call another constructor of the same class first, or the parent's constructor. A private constructor blocks outside creation and pairs with a factory (a static method that builds the object for you).
Make it yours · UDC Finance quote import (invented example)
Situation: at UDC Finance, quote data came in from a dealer spreadsheet. A new adviser imported a batch with a zero tax rate. Every quote was created, saved, and only failed later when the repayment schedule was calculated.
What I did: the quote class had a public parameterless constructor and public setters (methods that assign a field), so any state was allowed. I replaced it with a constructor that takes the amount, rate and term, checks them, and stores them in get-only properties. A short overload chains to it with the standard rate.
Result: an invalid quote cannot be created. The import either produces a valid quote or fails on the row, with the constructor naming the bad value. The check runs once and no later method has to defend against a zero rate.
What I'd say: constructors are where a class turns input into a valid object. If an object can exist in a broken state, every method that touches it needs a guard, and one of them will forget.
The code, simplified
Invented to show the shape, in C#. Tap Next to walk a quote from first use to the chained constructor.
UDC.sln · where this file sits
Quotes/
LoanQuote.cs · line 3 · 1 of 7private static readonly = one value shared by the type, set once and never changed.
Fix later in your repoThe batch, dates and counts are invented. The code shape matches quote origination at UDC: one constructor owns validation, and the short overload chains to it.
Say it out loud, then check
Show the 30-second answer
A class is a type, written once. An object is one instance (one filled-in copy) made from it at run time, with its own copy of the data.
An instance constructor has the class name and no return type; it runs for every new object and leaves it valid.
Types: parameterless, the default constructor that C# adds only when you write no instance constructor; parameterized and overloaded (several constructors with different parameters); static; and private. A copy constructor is one you write.
A static constructor runs once per type, before the first object or static member (a field or method marked static, shared by the type) of that class is used, and cannot be called by name. So it runs before the parameterless instance constructor, always, except when a static field initializer (a value written on the field itself) creates the class itself.
Then for each object: instance field initializers, then the constructor body. With a parent class (the base class it inherits from), the parent's constructor runs after the child's field initializers.
Chaining: a constructor can call another constructor of the same class first, or the parent's constructor. A private constructor blocks outside creation and pairs with a factory (a static method that builds the object for you).
Check your answer: tick what you said
You said 0 of 9
Then add your example: UDC Finance quote import (invented example)
Situation: at UDC Finance, quote data came in from a dealer spreadsheet. A new adviser imported a batch with a zero tax rate. Every quote was created, saved, and only failed later when the repayment schedule was calculated.
What I did: the quote class had a public parameterless constructor and public setters (methods that assign a field), so any state was allowed. I replaced it with a constructor that takes the amount, rate and term, checks them, and stores them in get-only properties. A short overload chains to it with the standard rate.
Result: an invalid quote cannot be created. The import either produces a valid quote or fails on the row, with the constructor naming the bad value. The check runs once and no later method has to defend against a zero rate.
What I'd say: constructors are where a class turns input into a valid object. If an object can exist in a broken state, every method that touches it needs a guard, and one of them will forget.
See it
Programfirst request
Loanthe class, written once
1/9A class is written once: says what every loan object holds and can do.On first use the type is readied: static field initializers, then the static constructor body.Then the object is built: its instance field initializer gives this loan its own id.The constructor body checks the values, then stores them in this object. returns the address. loan holds it, and one object now exists.A second repeats only the instance part; the static part already ran.The one-argument overload chains with this(...); the main constructor runs first. hides its constructor: you call its static method, never .Rate 0 reaches the constructor and throws. returns nothing, so no bad loan exists.
In plain words
A class is the form you design once; an object is one filled-in copy made from it at run time.
A constructor is the setup step that runs on every new object, so the object starts in a valid state instead of being patched later.
A static constructor is the one-time setup for the class itself, not for an object. Think of opening the office once before the first customer.
A private constructor is a door with no outside handle. Only the class itself, or a factory method it provides, can create the object.
Chaining is one constructor handing the shared work to another, so validation lives in one place instead of being copied into every overload.
The senior answer · about 2 minutes
Class and object
A class is a compile-time type: the compiler checks every use against it. An object is a run-time instance with its own fields. is the class; each new Loan(...) is a separate object.
A variable of a class type holds a reference, not the object. Two variables can point at one object, and assigning one to the other copies the reference. are the usual follow-up.
The constructor types
Instance constructors: parameterless, parameterized and overloaded. The parameterless one is only compiler-provided if the class declares no instance constructor; a static constructor does not count.
A static constructor initializes the type itself: static fields, a cache, a one-time read. It runs at most once per process, before the first static or instance member is used, and takes no arguments.
A private constructor blocks outside the class: a factory that returns a cached instance, or a singleton. For a helper with only static members, prefer a , which the compiler enforces; older code uses a private constructor for the same job.
A copy constructor is not a C# feature; it is an ordinary constructor that takes the same type and copies the fields. With reference fields, decide whether the copy is shallow or deep.
Order, exactly
For one class on first use: static field initializers in order, then the static constructor body. Once only. If it throws, the runtime wraps it in (the error .NET throws when a type's static setup failed), and the type stays unusable for the life of the process.
For each object: instance field initializers, then the base constructor, then this constructor's body. In a derived class the child's field initializers run before the base constructor.
With this(...), the chained constructor runs first. Field initializers run in the constructor that ultimately calls base(...), not twice.
allocates, runs the constructor, and returns the reference. If the constructor throws, no reference is returned and the object is garbage.
In production
Validate in the constructor so an invalid object cannot exist. Then every later method can trust its fields, and the failure points at the row that supplied the bad values.
Do not put I/O, a network call or a long read in a static constructor. It runs once, its failure is cached, and there is no retry until the process restarts. Build the object in the container at start-up instead, where a failure stops the deploy.
Keep constructors short and side-effect free apart from assigning fields. A constructor that sends email or writes to the database cannot be tested in isolation and runs again in every test that builds the object.
One object and two constructors
Follow one loan from the first to a rejected rate, and watch which constructor runs when.
Programthe caller
Loan classstatic and instance parts
Loan objectone per new
RateTableprivate constructor
declare Loan once
1/8A class is the type: written once, it declares what every loan object holds.First use readies the static part: static fields, then the static constructor. allocates an object, then its instance field initializer runs.The constructor body checks the values, stores them, and returns the object.A second repeats only the instance part; the static part already ran.The one-argument overload chains with this(...), so the main constructor runs first. hides its constructor: call the static method, never .A rate of 0 reaches the check and throws; returns nothing.
The story
Before
Before this, a quote could be created empty, saved, and given a rate later. A typo or a skipped field produced a row that looked fine until a repayment schedule divided by a zero rate. Nobody could say where the bad state entered, because every setter accepted anything.
In the lending API
The key file: the static part runs once, the checks run for every object, and the overload chains to them.
Only the key lines are shown; Deep walks the whole file.
Lending.sln · where this file sits
src/Domain/Servicing/
⋯ 9 lines in Deep⋯ 2 lines in Deep⋯ 9 lines in Deep
Loan.cs · line 7 · 1 of 3Runs once per process, before the first object; the static fields are already set. No parameters, and never called by name.
The code, file by file
Two files and a caller, .NET 8. Tap Next to follow the first , a second object, a chained overload, a private constructor and a rejected rate.
Lending.sln · where these 3 files sit
src/
Api/
Domain/Servicing/
Diagram · step 1A class is written once: says what every loan object holds and can do.
Programfirst request
Loanthe class, written once
Program.cs · line 3 · 1 of 5First use of : the type is readied before this call returns (see Loan.cs). One loan, 500,000 at 9.5% for 60 months. The m suffix marks a decimal literal; the underscore is only a digit separator.
What they ask next
The follow-ups interviews really ask. Answer out loud, then tap to check.
ReportedWhat are the different types of constructors?
Instance constructors: parameterless (often called the default constructor) and parameterized/overloaded. Static constructors initialize the type itself. Private constructors restrict creation. C# has no separate copy constructor; it is an ordinary constructor that takes the same type.
ReportedWhat is the difference between a class and an object?
A class is the type you declare once: fields, properties, methods, and the rules. An object is one instance of that type at run time, with its own field values. The class is the compiler's contract; the object is the thing in memory.
ReportedWhat is constructor chaining, and in what order do the parts run?
Chaining is one constructor calling another before its own body. this(...) calls another constructor of the same class; base(...) calls the parent's constructor. The target constructor runs first, including field initializers, then your body.
Answer, then open the next level. That is the order an interviewer digs in.
Reporteda candidate was asked Intervieweran interviewer asks it
ReportedWhat are the different types of constructors?
Instance constructors: parameterless (often called the default constructor) and parameterized/overloaded. Static constructors initialize the type itself. Private constructors restrict creation. C# has no separate copy constructor; it is an ordinary constructor that takes the same type.
ReportedIf a class has a static constructor and a default constructor, which runs first?
The static one. The type is initialized before the first instance is created: static field initializers, then the static constructor body. Then, for the object, instance field initializers, then the instance constructor body. The one exception is a static field initializer that creates the class itself; that instance constructor runs first.
If I write only a static constructor, does C# still add a public parameterless one?
Yes. A static constructor does not count as an instance constructor, so the compiler still adds a public parameterless instance constructor when no instance constructor is declared.
publicclassLoan
{
static Loan() { }
}
var l = newLoan(); // allowed
ReportedWhat is the difference between a class and an object?
A class is the type you declare once: fields, properties, methods, and the rules. An object is one instance of that type at run time, with its own field values. The class is the compiler's contract; the object is the thing in memory.
A class is a reference type, so the object lives on the managed heap. The variable holds a reference to it. Two variables can point at one object; copying the variable copies the reference, not the object. .
Is a class itself an object?
At run time the runtime has a type object that describes the class, reachable through typeof. But that is metadata, not an instance of your class. Your class's constructor creates instances of the class, not new types.
ReportedWhat is constructor chaining, and in what order do the parts run?
Chaining is one constructor calling another before its own body. this(...) calls another constructor of the same class; base(...) calls the parent's constructor. The target constructor runs first, including field initializers, then your body.
One place owns the invariant (a rule the object must always satisfy, such as rate > 0). Every overload reaches the same checks, so a new overload cannot silently skip one. The overload usually supplies a default, then delegates.
public Loan(decimal amount)
: this(amount, 9.5m, 60) { }
Does the base constructor run before or after the child's field initializers?
After. In C#, the child's instance field initializers run, then the base constructor runs its own field initializers and body, then the child's body. This surprises people who expect the parent to run first.
classChild : Parent
{
int _x = Log("child field");
}
When would you use a private constructor?
Three common cases: a factory that controls creation and returns a cached or validated instance; a singleton; and a class with only static members in older code, where a static class is the modern choice. A class whose only constructors are private also cannot be subclassed from outside: class Child : Loan fails to compile, because a child cannot call a base constructor.
What is the difference between a private constructor and a sealed class?
A private constructor stops outside code creating the type (and stops subclassing). stops subclassing but still allows a public constructor and normal instances. They solve different problems.
What happens if you declare no constructor at all?
C# adds a public parameterless instance constructor that does nothing beyond the field initializers and the base call. It disappears as soon as you declare any instance constructor, so adding one can break callers that used new Foo().
var l = newLoan(); // compiler-added ctorpublicclassLoan { }
Does C# have a copy constructor?
Not built in. You can write a constructor that takes the same type and copies fields. For reference fields, choose shallow (share the reference) or deep (copy the inner objects too, so the copy cannot change the original).
No. A constructor cannot be (marked to run asynchronously) and cannot (pause until an async call finishes), because an object must be fully built before the caller gets the reference. Use a static async factory that awaits the work, then calls a private constructor with the finished values.
// _repo is a static data-access objectprivatestaticreadonly ILoanRepo _repo
= newLoanRepo();
publicstaticasyncTask<Loan>
LoadAsync(int id)
{
var data = await _repo.GetAsync(id);
returnnewLoan(data);
}
What is a primary constructor in C# 12?
Parameters written on the class declaration itself, captured by the class (stored as fields its methods can use). They are a concise way to receive constructor arguments, not a replacement for validation: the compiler does not add checks. Use them for small classes, and still validate in the body or a helper.
Why validate in the constructor instead of a setter or a service?
The constructor is the only place every instance must pass through. If it rejects invalid input, no later method needs to defend against it, and the failure names the row that supplied the values. Setters can be forgotten; a service can be bypassed.
Production bugs
Coming Not written yet: the card pass adds it.
Production incident: NZ quotes failed on one instance after a rate-file rename
P2 · serious, has a workaroundUDC Financea wrong settingNZ quote API on App Service
Composed, not a real event at UDC Finance. The mechanism is real .NET: a static constructor runs once per process, and if it throws the runtime wraps the error in `TypeInitializationException` and keeps the type unusable until the process restarts. Dates, counts, names and ticket numbers are composed.
The story in 5 lines
On 30 Sep one of the three quote API instances (separate copies of the app running side by side) started returning 500 for every NZ quote. The other two were fine, so the dealer desk saw failures on roughly one request in three.
The deploy had renamed the rate file and changed the setting, but still read a hard-coded nz-rates.json in its static constructor.
The file was missing, the static constructor threw, and .NET cached the failure: every later use threw (the error .NET throws when a type's static setup failed) without retrying the file.
Fix: make the table a normal singleton (one shared object for the whole app), built by the container (the .NET object that builds and hands out shared services) at start-up, and let a bad file stop the deploy instead of the first quote.
Prevent: a start-up test that reads the rate file, and a 5xx alert (server errors, 500–599) per instance, not only for the whole service.
Who's who (4 people)
You
.NET developer on the vendor team. Finds the cause and writes the fix.
Tech lead
Vendor senior. Reviews the change, runs the postmortem (the review held after an incident).
L2 pod
Vendor support. Takes the ticket, runs the logs query.
UDC Finance operations lead
Owns the dealer quote desk. Decides how the failed quotes are recovered.
Tap a step. The map lights the place where it happens.
UDC portaldealer quote desk
APIx3
NzRateTablethe broken type
RateJSON file
L2 + youon call
quote request
500
same 500 on retry
1/4 Detect
Detect: one of three instances returns 500 for every NZ quote. The other two are fine.
Wed 30 Sep, 09:10 NZDTUDC Finance operations lead, then the L2 pod
What: the dealer desk reports that NZ quotes fail with a 500, but only some of the time. A retry sometimes works.
Why it looked random: (Azure's managed web hosting) has three instances behind a load balancer (spreads requests across instances). The 08:55 deploy replaced one instance at a time: App_0 restarted into the new package, which held only nz-rates-v2.json, while the other two instances still ran the old code, already loaded in memory. Requests that landed on App_0 failed; the other two served normally.
How we saw it: filtered the exceptions (error rows from the app) by instance. Every 500 was on App_0, and every message held with inside.
App Insights (Azure's log store): errors by instance
// KQL = App Insights query language.// exceptions rows are errors.// cloud_RoleInstance names the instance.
exceptions
| where timestamp between (
datetime(2026-09-29) ..
datetime(2026-10-01))
| where outerMessage has "NzRateTable"
| summarize count() by cloud_RoleInstance,
bin(timestamp, 10m)
In theory
A 5xx alert per instance: page when one instance's failure rate passes 5%, even if the service average looks healthy.
In practice
The service-level alert watched the whole app. One bad instance was a third of traffic, below the 50% threshold, so nobody was paged.
Try it yourself · 10 minutes, on your Mac
dotnet new console -n StaticLab. Add with a static constructor that reads a file that does not exist.
Call twice, each in a try/catch. The first call throws ; so does the second, without trying the file again.
Move the read into an instance constructor and call it at start-up. A missing file now fails once, at start-up, with in the inner exception.
Add a unit test that starts the app with the file missing and expects start-up to fail.
You should see
A static constructor runs once. If it throws, the type stays broken for the life of the process.
The senior move
"A static constructor is a one-time initializer with no retry: if it does I/O and throws, the whole type is dead until restart. I load shared state in the container at start-up, so a bad file fails the deploy instead of a customer request."
SourcesSourced: static constructors run once per type before first use; an exception there becomes , the type cannot be used again in that process, and the real error is in (C# programming guide and .NET 8 runtime behaviour). Composed: UDC Finance's systems, dates, instance counts, names, ticket and numbers, and the (standard columns).
Traps
Don't saySay the static constructor runs once per object.SayIt runs once per type for the life of the process, before the first object or static member is used.
Don't saySay the base constructor always runs before the child's field initializers.SayIn C#, the child's field initializers run first, then the base constructor, then the child's body.
Don't saySay a private constructor makes the class sealed.SayIt blocks outside , and a class with only private constructors cannot be subclassed from outside, but is the explicit keyword for stopping inheritance.
Don't saySay C# has a default copy constructor.SayIt does not; a copy constructor is one you write, and you choose shallow or deep copying.
Don't sayPut a database or file read in a static constructor.SayIt runs once and its failure is cached, so there is no retry until the process restarts. Build it at start-up and fail the deploy instead.
Traps
What should you say instead? Tap to check.
Don't saySay the static constructor runs once per object.
Say instead
It runs once per type for the life of the process, before the first object or static member is used.
Don't saySay the base constructor always runs before the child's field initializers.
Say instead
In C#, the child's field initializers run first, then the base constructor, then the child's body.
Don't saySay a private constructor makes the class sealed.
Say instead
It blocks outside , and a class with only private constructors cannot be subclassed from outside, but is the explicit keyword for stopping inheritance.
Don't saySay C# has a default copy constructor.
Say instead
It does not; a copy constructor is one you write, and you choose shallow or deep copying.
Don't sayPut a database or file read in a static constructor.
Say instead
It runs once and its failure is cached, so there is no retry until the process restarts. Build it at start-up and fail the deploy instead.
Live coding
Easy first, then harder. Set a timer and type it before you look.
Task 1
Reportedeasy · 15 minutes
Write a class with two constructors: one takes amount and rate, the other takes amount and uses a standard 9.5% rate. Both must reject a non-positive amount or rate, and both must produce an object with get-only properties (set only inside the constructor).
A new list alone is not enough: the same charge objects are still shared.
Copy each mutable charge into a new object inside the loop.
Show a solution
Lending.sln · where this file sits
What the interviewer checks
Creates a new list, not a copy of the list reference.
Creates a new for every element, copying its fields.
A test changes the copy's first charge and asserts the original is unchanged.
Can explain when a shallow copy would be safe: when the elements are immutable.
With AI tools
AI assistants often generate the easiest shape: a parameterless constructor plus public setters, which lets an invalid object exist. For example, before: new Loan() then loan.Rate = 0;; after: new Loan(500_000m, 9.5m, 60), which rejects a zero rate. In review I ask for the constructor that makes the invalid state impossible, then ask for a test that tries to create it. The same review catches a static constructor doing I/O: it runs once, and its failure is cached for the life of the process.