C# – Reflection, Expression Trees, Assemblies & JSON Serialization
1. What is the difference between Reflection and Expression Trees?
Reflection is used to inspect and interact with types, properties, and methods at runtime.
Expression Trees represent code as a tree structure that can be inspected, modified, or compiled into executable code.
Comparison
|
Reflection |
Expression Trees |
|---|---|
|
Inspects type metadata |
Represents code logic |
|
Uses |
Uses |
|
Can dynamically invoke methods |
Can compile expressions into delegates |
|
Useful for metadata inspection |
Useful for dynamic LINQ queries |
|
Repeated dynamic invocation can be slower |
Compiled delegates can be reused efficiently |
Example
Reflection:
using System.Reflection;
Type type = typeof(Employee);
PropertyInfo? property = type.GetProperty("Name");
Console.WriteLine(property?.Name);
Output:
Name
Expression Tree:
using System.Linq.Expressions;
Expression<Func<int, int>> expression = x => x * 2;
Func<int, int> function = expression.Compile();
Console.WriteLine(function(5));
Output:
10
Explanation
-
Reflection retrieves information about the
Nameproperty. -
The expression tree represents the logic
x => x * 2. -
Compile()converts the expression tree into an executable delegate.
Real-world usage
Reflection
|
+-- Dependency Injection
+-- Reading Attributes
+-- Plugin Systems
Expression Trees
|
+-- Entity Framework Core
+-- Dynamic LINQ Queries
+-- Query Builders
Key Points
-
Reflection focuses on type metadata.
-
Expression trees focus on code structure and behavior.
-
EF Core uses expression trees to translate LINQ queries into SQL.
-
Expression trees can also be inspected and transformed without compiling them.
2. What are Assemblies, Namespaces, and Metadata?
These three concepts are fundamental to .NET application organization.
Definitions
|
Concept |
Description |
|---|---|
|
Assembly |
Compiled unit of .NET code, usually a DLL or EXE |
|
Namespace |
Logical grouping of related types |
|
Metadata |
Information about types, methods, properties, and references |
Example
namespace MyApplication.Services
{
public class EmployeeService
{
public void Display()
{
Console.WriteLine("Employee Service");
}
}
}
After compilation:
MyApplication
|
+-- MyApplication.dll (Assembly)
|
+-- MyApplication.Services (Namespace)
|
+-- EmployeeService (Class)
|
+-- Display() (Method)
Explanation
Assembly:
-
A compiled deployment and versioning unit.
-
Contains IL code and metadata.
-
Examples:
MyApplication.dll,System.Text.Json.dll.
Namespace:
-
Organizes related classes and interfaces.
-
Prevents naming conflicts.
-
One namespace can span multiple assemblies.
Metadata:
-
Describes classes, properties, methods, and their signatures.
-
Stored in assemblies.
-
Used by the CLR and reflection.
Key Points
-
Assembly is a physical compiled unit.
-
Namespace is a logical grouping.
-
Metadata describes the contents of an assembly.
-
A single assembly can contain multiple namespaces.
3. What is the difference between Early Binding and Late Binding?
Early Binding means the compiler determines the type and method to call at compile time.
Late Binding means method resolution happens at runtime, commonly using reflection or dynamic.
Comparison
|
Early Binding |
Late Binding |
|---|---|
|
Resolved at compile time |
Resolved at runtime |
|
Compile-time type checking |
Runtime member resolution |
|
Generally faster |
Generally more overhead |
|
Compile-time errors for invalid members |
May throw runtime exceptions |
|
Uses normal typed calls |
Uses reflection or |
Example
Early Binding:
public class Employee
{
public void Display()
{
Console.WriteLine("Employee Details");
}
}
Employee emp = new Employee();
emp.Display();
Late Binding:
dynamic emp = new Employee();
emp.Display();
Explanation
-
In early binding, the compiler checks whether
Display()exists. -
In late binding,
dynamicdefers member resolution until runtime. -
If the method does not exist, late binding produces a runtime exception.
Flow
Early Binding
|
+-- Compile Time
| |
| +-- Type Checking
| +-- Member Resolution
|
+-- Execution
Late Binding
|
+-- Compile Time
| |
| +-- Dynamic Call
|
+-- Runtime
|
+-- Resolve Member
+-- Invoke Method
Key Points
-
Early binding provides better compile-time safety.
-
Late binding provides runtime flexibility.
-
Reflection and
dynamicsupport late binding. -
Virtual method dispatch also occurs at runtime, but it is not normally classified as late binding in C#.
4. How do you exclude or rename properties during JSON serialization?
In System.Text.Json, we can use attributes to control JSON property names and exclude properties.
Two commonly used attributes are:
-
[JsonIgnore]– Excludes a property from JSON serialization. -
[JsonPropertyName]– Changes the JSON property name.
Example
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Employee
{
public int Id { get; set; }
[JsonPropertyName("employee_name")]
public string Name { get; set; } = "";
[JsonIgnore]
public string Password { get; set; } = "";
}
class Program
{
static void Main()
{
var emp = new Employee
{
Id = 101,
Name = "Syed",
Password = "Secret123"
};
string json = JsonSerializer.Serialize(emp);
Console.WriteLine(json);
}
}
Output:
{
"Id": 101,
"employee_name": "Syed"
}
Formatted for readability; the actual output is one line.
Explanation
-
Idis serialized normally. -
Nameis renamed toemployee_name. -
Passwordis excluded from the JSON output.
Additional Options
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Email { get; set; }
This excludes Email when its value is null.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int Age { get; set; }
This excludes Age when its value is the default integer value (0).
Key Points
-
[JsonIgnore]excludes properties. -
[JsonPropertyName]renames properties. -
[JsonIgnore(Condition = ...)]provides conditional exclusion. -
These attributes are useful when controlling Web API response formats.
-
For sensitive data, dedicated response DTOs are generally preferable to relying only on
[JsonIgnore].
5. What is Source-Generated JSON Serialization?
Source-generated JSON serialization is a feature of System.Text.Json that generates serialization-related code during compilation instead of relying entirely on runtime reflection.
It improves performance in certain scenarios and supports Native AOT applications.
Traditional vs Source-Generated Serialization
Traditional JSON Serialization
|
v
C# Object
|
v
Runtime Metadata / Reflection
|
v
JSON Output
Source-Generated Serialization
|
v
Compile Time
|
v
Generate JSON Metadata/Code
|
v
Runtime
|
v
JSON Output
Example
Step 1: Create a model
public class Employee
{
public int Id { get; set; }
public string Name { get; set; } = "";
}
Step 2: Create a JSON serializer context
using System.Text.Json.Serialization;
[JsonSerializable(typeof(Employee))]
public partial class EmployeeJsonContext
: JsonSerializerContext
{
}
Step 3: Serialize the object
using System.Text.Json;
var employee = new Employee
{
Id = 101,
Name = "Syed"
};
string json = JsonSerializer.Serialize(
employee,
EmployeeJsonContext.Default.Employee
);
Console.WriteLine(json);
Output:
{"Id":101,"Name":"Syed"}
Explanation
-
[JsonSerializable(typeof(Employee))]identifies the type for source generation. -
JsonSerializerContextprovides generated serialization metadata. -
The compiler generates the required serialization support.
-
EmployeeJsonContext.Default.Employeesupplies the generated type information.
Advantages
-
Reduces runtime reflection requirements.
-
Can improve startup performance.
-
Can reduce memory allocation in some scenarios.
-
Supports trimming and Native AOT.
-
Can improve serialization throughput when optimized serialization generation is enabled.
Key Points
-
Available in modern .NET through
System.Text.Json. -
Uses compile-time code generation.
-
Requires a partial class derived from
JsonSerializerContext. -
Especially useful for high-performance APIs, microservices, and Native AOT applications.
-
Performance gains depend on the serialization mode, payload, and application workload.
Quick Interview Revision
|
Question |
Important Answer |
|---|---|
|
Reflection vs Expression Trees |
Runtime metadata inspection vs representation of code logic |
|
Assembly |
Compiled .NET code unit (DLL/EXE) |
|
Namespace |
Logical grouping of types |
|
Metadata |
Information describing types and members |
|
Early Binding |
Compile-time member resolution |
|
Late Binding |
Runtime member resolution |
|
|
Excludes a JSON property |
|
|
Renames a JSON property |
|
Source-Generated JSON |
Generates serialization metadata/code at compile time |
Interview Tip: For a .NET Tech Lead interview, focus particularly on Reflection vs Expression Trees, early vs late binding, and JSON serialization attributes. These concepts are relevant to Dependency Injection, EF Core, and ASP.NET Core Web API development.