C#
block equivalent
programming language
code structure
software development

With block equivalent in C?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

VB.NET has a With block that lets you call multiple members on the same object without repeating the variable name. C# has no direct equivalent. However, C# offers several constructs that achieve similar conciseness: object initializers, local variables with short names, extension methods, and the using alias. Each approach trades off readability, safety, and applicability differently.

The VB.NET With Block

vb
1With myButton
2    .Text = "Click Me"
3    .Width = 200
4    .Height = 50
5    .Enabled = True
6End With

Inside the With block, the dot prefix refers to myButton. Every member access is implicitly scoped to that object.

C# Alternative 1: Object Initializer

When creating a new object, C# object initializers provide the closest syntax:

csharp
1var button = new Button
2{
3    Text = "Click Me",
4    Width = 200,
5    Height = 50,
6    Enabled = true
7};

This only works at construction time. You cannot use it to configure an existing object after creation.

C# Alternative 2: Short Local Variable

The simplest workaround for an existing object — assign it to a short-named variable:

csharp
1var b = existingButton;
2b.Text = "Click Me";
3b.Width = 200;
4b.Height = 50;
5b.Enabled = true;

Since b is a reference (for reference types), changes apply to the original object. This is the most common pattern in C# codebases.

C# Alternative 3: Extension Method for Fluent Configuration

Create a generic extension method that accepts an Action<T>:

csharp
1public static class ObjectExtensions
2{
3    public static T Apply<T>(this T obj, Action<T> action)
4    {
5        action(obj);
6        return obj;
7    }
8}
9
10// Usage
11existingButton.Apply(b =>
12{
13    b.Text = "Click Me";
14    b.Width = 200;
15    b.Height = 50;
16    b.Enabled = true;
17});

The Apply method passes the object into the lambda, simulating a With block. Returning obj enables chaining if needed.

C# Alternative 4: Fluent Builder / Method Chaining

Many C# libraries use fluent APIs that return this from each method:

csharp
1new HostBuilder()
2    .ConfigureServices(services => services.AddSingleton<IMyService, MyService>())
3    .ConfigureLogging(logging => logging.AddConsole())
4    .Build();

You can design your own classes to support this pattern:

csharp
1public class ButtonBuilder
2{
3    private readonly Button _button = new();
4
5    public ButtonBuilder WithText(string text) { _button.Text = text; return this; }
6    public ButtonBuilder WithSize(int w, int h) { _button.Width = w; _button.Height = h; return this; }
7    public Button Build() => _button;
8}
9
10var button = new ButtonBuilder()
11    .WithText("Click Me")
12    .WithSize(200, 50)
13    .Build();

C# Alternative 5: using static for Scoped Methods

When calling many static methods from the same class, using static reduces repetition:

csharp
1using static System.Math;
2
3double result = Sqrt(Pow(x, 2) + Pow(y, 2));
4// Without 'using static': Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2))

This does not apply to instance members but eliminates the class prefix for static calls.

C# 12 Primary Constructors and init Properties

Modern C# provides init properties and required members that reduce boilerplate at construction:

csharp
1public class Button
2{
3    public required string Text { get; init; }
4    public int Width { get; init; }
5    public int Height { get; init; }
6}
7
8var button = new Button
9{
10    Text = "Click Me",
11    Width = 200,
12    Height = 50
13};
14// button.Text = "Changed"; // ERROR: init-only property

This enforces immutability after construction — a different goal from With, but it addresses the same verbosity problem.

Comparison Table

ApproachWorks on Existing ObjectsType-SafeRequires Extra Code
Object initializerNo (creation only)YesNo
Short local variableYesYesNo
Apply extensionYesYesOne-time extension method
Fluent builderDepends on designYesPer-class builder
using staticStatic members onlyYesNo

Common Pitfalls

  • Using object initializers on existing objects: Object initializers only work in new expressions. You cannot write existingButton { Text = "X" } — use a local variable or lambda instead.
  • Value type gotcha with short variable alias: For structs, var b = existingStruct copies the value. Changes to b do not affect the original. Use ref var b = ref existingStruct (C# 7+) if you need a reference.
  • Overusing the Apply pattern: Wrapping every property assignment in a lambda adds a closure allocation and reduces debuggability. Use it sparingly for configuration-heavy sections, not for one or two property sets.
  • Fluent builders hiding mutation: If a builder mutates the object in place (instead of creating copies), calling .Build() twice returns the same modified object. Document whether the builder is reusable or single-use.
  • Assuming C# will add a with keyword for classes: C# records have with expressions, but they create a copy — they do not mutate the original. var b2 = b1 with { Text = "New" } gives a new record instance, not a With block.

Summary

  • C# has no direct With block equivalent from VB.NET
  • Object initializers handle the creation case cleanly
  • For existing objects, assign to a short local variable — simplest and most idiomatic
  • The Apply<T> extension method simulates a With block using a lambda
  • Fluent APIs and method chaining provide a similar developer experience for well-designed classes
  • C# records support with expressions, but they create copies rather than mutating in place

Course illustration
Course illustration

All Rights Reserved.