← Back to Articles         
C# – Reflection, Expression Trees, Assemblies

C# – Reflection, Expression Trees, Assemblies

Published on 12 Oct 2026     6 min read C#
Reflection

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 System.Reflection

Uses System.Linq.Expressions

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 Name property.

  • 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 dynamic

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, dynamic defers 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 dynamic support 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

  • Id is serialized normally.

  • Name is renamed to employee_name.

  • Password is 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

  1. [JsonSerializable(typeof(Employee))] identifies the type for source generation.

  2. JsonSerializerContext provides generated serialization metadata.

  3. The compiler generates the required serialization support.

  4. EmployeeJsonContext.Default.Employee supplies 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

[JsonIgnore]

Excludes a JSON property

[JsonPropertyName]

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.

← Back to Articles