84

I know VB.Net and am trying to brush up on my C#. Is there a With block equivalent in C#?

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Dan Appleyard
  • 7,405
  • 14
  • 49
  • 80
  • 1
    I know there is a dupe of this on SO, but for the life of me I can't figure out a search query that can find it. – ctacke Jan 26 '09 at 23:14
  • 6
    @ctacke: I thought "can't be that hard..." , then spent 10 minutes unsuccessfully trying to find it!.... – Mitch Wheat Jan 27 '09 at 10:04
  • google knows: "with c# site:stackoverflow.com" gives: http://stackoverflow.com/questions/1175334/whats-the-c-sharp-equivalent-to-the-with-statement-in-vb And http://stackoverflow.com/questions/1063429/equivalence-of-with-end-with-in-c – schoetbi Jun 30 '14 at 11:07

20 Answers20

60

Although C# doesn't have any direct equivalent for the general case, C# 3 gain object initializer syntax for constructor calls:

var foo = new Foo { Property1 = value1, Property2 = value2, etc };

See chapter 8 of C# in Depth for more details - you can download it for free from Manning's web site.

(Disclaimer - yes, it's in my interest to get the book into more people's hands. But hey, it's a free chapter which gives you more information on a related topic...)

Jaymin
  • 2,879
  • 3
  • 19
  • 35
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    This is not the same at all as this involves creating an instance of a class, whereas With block does not. – John Stock Apr 28 '17 at 21:06
  • 3
    @JohnStock: Hence "no direct equivalent for the general case". In situations where you were using with `With` statement just for initialization, however, it's still the corresponding idiom. – Jon Skeet Apr 29 '17 at 06:05
  • This initialization signature was mostly the product of Lambda expressions implementation than anything else. It is the closest signature available in C# to VB's With short-hand. – GoldBishop Oct 03 '17 at 12:56
  • @GoldBishop: It's independent of lambda expressions - but both were created to support LINQ in C# 3. – Jon Skeet Oct 03 '17 at 12:57
  • Causality instead of Correlation? – GoldBishop Oct 03 '17 at 12:58
  • @GoldBishop: The causality is "both are required to make LINQ work nicely". Each feature *could* have been implemented independently without the other, if LINQ hadn't been important. (Indeed, anonymous methods in C# 2 are very similar to lambda expressions that are converted to delegates.) There's a more causal relationship between `var` and anonymous types. – Jon Skeet Oct 03 '17 at 13:00
  • Anyway, where can I vote for adding a general `with` statement to a future C# version? :) – maf-soft Jun 17 '18 at 14:20
  • 1
    @maf-soft: Well https://github.com/dotnet/csharplang would be the place, but I can't see it happening. I can imagine `with` being used for immutable types, but not the general VB case. – Jon Skeet Jun 17 '18 at 17:54
  • **This answer is outdated.** Please refer to [my answer](https://stackoverflow.com/a/70658266/9988162). – Despacito 2 Jan 10 '22 at 20:15
32

This is what Visual C# program manager has to say: Why doesn't C# have a 'with' statement?

Many people, including the C# language designers, believe that 'with' often harms readability, and is more of a curse than a blessing. It is clearer to declare a local variable with a meaningful name, and use that variable to perform multiple operations on a single object, than it is to have a block with a sort of implicit context.

Sven Niehus
  • 487
  • 5
  • 24
Gulzar Nazim
  • 51,744
  • 26
  • 128
  • 170
  • 7
    Dead link. I think this is its new spot: http://blogs.msdn.com/b/peterhal/archive/2005/07/05/435760.aspx – Keith Jul 04 '12 at 22:42
  • 4
    Link's dead again. Here's a new one from the C# FAQ: http://blogs.msdn.com/b/csharpfaq/archive/2004/03/11/why-doesn-t-c-have-vb-net-s-with-operator.aspx – KyleMit Feb 06 '14 at 15:11
  • 4
    Disagree completely. I can't format the code example I would like to in a comment but right now I have a whole `get` littered with `SKYLib.AccountsPayable.Client.ApiAuthorization.Authorization` instead of `With SKYLib.AccountsPayable.Client.ApiAuthorization.Authorization { .AuthToken = "123" .RefreshToken = "456" ... }`. – SteveCinq Aug 03 '18 at 05:43
  • 2
    Unless you're working with a rather unusual library, there's no reason you can't cache the authorization object. `var auth = SKYLib.AccountsPayable.Client.ApiAuthorization.Authorization; auth.AuthToken = "123"; auth.RefreshToken = "456"; ... `. In other words, your problem could be solved by doing exactly what the answer that you're complaining about prescribes. – snarf Jul 11 '20 at 15:42
  • You should always give your variables meaningful names. Nevertheless, it sometimes woudl be useful if you could create a separate scope for a newly created object. Creating that scope manually by `{ var o = new object(); o.use (); ..}` is the only good possibility so far to achieve that. – Tobias Knauss Jan 08 '21 at 12:59
  • Anybody talked about the fact that we can add methods/calls between properties setter in a WITH block, all C# alternative I saw can't do that. – BlinkSun Oct 08 '21 at 15:43
  • Who are the "Many People"? I use both C# and VB.NET and a WITH would be nice to have in C# and doesn't "harm readability" ... if anything the over use of LINQ harms readability ... too much pandering to elitist mentality rather than a productive one. – Rob Ainscough Jan 05 '23 at 21:48
22

As the Visual C# Program Manager linked above says, there are limited situations where the With statement is more efficient, the example he gives when it is being used as a shorthand to repeatedly access a complex expression.

Using an extension method and generics you can create something that is vaguely equivalent to a With statement, by adding something like this:

    public static T With<T>(this T item, Action<T> action)
    {
        action(item);
        return item;
    }

Taking a simple example of how it could be used, using lambda syntax you can then use it to change something like this:

    updateRoleFamily.RoleFamilyDescription = roleFamilyDescription;
    updateRoleFamily.RoleFamilyCode = roleFamilyCode;

To this:

    updateRoleFamily.With(rf =>
          {
              rf.RoleFamilyDescription = roleFamilyDescription;
              rf.RoleFamilyCode = roleFamilyCode;
          });

On an example like this, the only advantage is perhaps a nicer layout, but with a more complex reference and more properties, it could well give you more readable code.

Jaymin
  • 2,879
  • 3
  • 19
  • 35
RTPeat
  • 640
  • 6
  • 13
  • 5
    I don't really see the advantage of what your example shows. The original code (pre-lambda) is the [objectinstance].[property] = [value]. The lambda code is basically just changing the updateRoleFamily with rf. – Dan Appleyard May 28 '09 at 14:15
  • 3
    Try it with a longer reference to the object instance and many more properties. In the above example you are simplifying updateRoleFamily to rf and setting two properties, which you are correct, isn't a big gain. If however your object instance is something like myDataStructure.GetButton(44), and you have to set ten properties it could make it more readable to use a lambda or set a local variable. Like the original VB With statement, it is only a little bit of syntactic sugar, that you can take or leave. – RTPeat May 29 '09 at 09:11
  • 4
    @DanAppleyard I see it simply as encapsulation, which can be be very useful at times. But then I'm biased, having come from VB.NET where With often came in handy and I really missed it in C#. No readability issues with anyone at all familiar with C#, just makes coding a little bit easier, esp. when dealing with long object names. – ingredient_15939 Jul 31 '14 at 09:56
  • 6
    Seems like setting a local variable would be more efficient AND more readable. `var rf = myDataStructure.GetButton(44);` I don't see this being syntactic sugar at all. It's just a convoluted way of setting a local variable. *"Just because you can doesn't mean you should."* – crush Oct 29 '15 at 03:12
  • the way out of this non-issue would be to pick more meaningful and less verbose names to begin with: lose the useless `RoleFamily` prefixes and you won't need any of these convoluted workarounds. – kuroi neko Aug 09 '21 at 05:16
14

About 3/4 down the page in the "Using Objects" section:

VB:

With hero 
  .Name = "SpamMan" 
  .PowerLevel = 3 
End With 

C#:

//No "With" construct
hero.Name = "SpamMan"; 
hero.PowerLevel = 3; 
Timothy Carter
  • 15,459
  • 7
  • 44
  • 62
13

No, there is not.

Guulh
  • 284
  • 2
  • 7
10

The with keywork is introduced in C# version 9! you can use it to create copy of object like follows

Person brother = person with { FirstName = "Paul" };

"The above line creates a new Person record where the LastName property is a copy of person, and the FirstName is "Paul". You can set any number of properties in a with-expression. Any of the synthesized members except the "clone" method may be written by you. If a record type has a method that matches the signature of any synthesized method, the compiler doesn't synthesize that method."

UPDATE:

At the time this answer is written, C#9 is not officially released but in preview only. However, it is planned to be shipped along with .NET 5.0 in November 2020

for more information, check the record types.

Benzara Tahar
  • 2,058
  • 1
  • 17
  • 21
6

What I do is use a csharp ref keyword. For example:

ref MySubClassType e = ref MyMainClass.MySubClass;

you can then use the shortcut like: e.property instead of MyMainClass.MySubClass.property

Walter Zydhek
  • 293
  • 4
  • 10
  • 4
    This is called [ref locals](https://learn.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/ref-returns#ref-locals) and was introduced in C# 7.0. – maf-soft Jun 17 '18 at 14:07
  • Interesting. Though in the current discussion, imho `var e = MyMainClass.MySubClass;` works just as well. OTOH, for a `struct`, this answer is quite useful: `... ref MyMainClass.MyLargeStruct;`. – ToolmakerSteve May 24 '22 at 23:11
5

Most simple syntax would be:

{
    var where = new MyObject();
    where.property = "xxx";
    where.SomeFunction("yyy");
}

{
    var where = new MyObject();
    where.property = "zzz";
    where.SomeFunction("uuu");
}

Actually extra code-blocks like that are very handy if you want to re-use variable names.

Wouter Schut
  • 907
  • 2
  • 10
  • 22
  • Although I do wish they'd finally add a With block,I like this approach as it doesn't require any extra libraries or custom code and it successfully prevents the object from being mutated outside of the scope. – Merkle Groot Jul 28 '20 at 17:53
4

You could use the argument accumulator pattern.

Big discussion about this here:

http://blogs.msdn.com/csharpfaq/archive/2004/03/11/87817.aspx

BBetances
  • 925
  • 1
  • 14
  • 23
  • This is a good alternative, and the pattern is nice for lots of reasons other than replacing "with". Another option is a utility method, like I describe here: http://stackoverflow.com/questions/601153/missing-the-with-keyword-in-c/601237#601237 – Gabe Moothart May 14 '09 at 18:50
  • 1
    Link doesn't work. Please include a code snippet in the future. Thanks. – camainc Feb 10 '22 at 16:17
  • Link has expired - no "argument accumulator pattern" at destination. – Apsis0215 Jun 07 '23 at 19:55
3

C# 9 and above:

The with keyword has finally been added!

It only supports record types.

Usage

The instance on the left hand side of the with keyword is copied and all of the mentioned fields on its right hand side are modified by their according value to return a new instance.

Example

Suppose we have the following record type:

public record Model(string Prefix, string Location, bool CoolLocation, bool HasCitizens);

And we have following original model initialized:

var model = new Model("Hello", "World", true, true);

We want to create a new model with all of the same fields except for Location and HasCitizens. We could do it in the following way:

var model2 = model with { Location = "Mars", HasCitizens = false };
   // Prefix = "Hello"
   // Location = "Mars"
   // CoolLocation = true
   // HasCitizens = false

C# 10 and above:

The with keyword can now additionally be used for struct and anonymous types.

More info to the with keyword can be found within the official docs

Despacito 2
  • 444
  • 2
  • 10
2

Sometimes you can get away with doing the following:

var fill = cell.Style.Fill;
fill.PatternType = ExcelFillStyle.Solid;
fill.BackgroundColor.SetColor(Color.Gray);
fill.PatternColor = Color.Black;
fill.Gradient = ...

(Code sample for EPPLus @ http://zeeshanumardotnet.blogspot.com)

Sean
  • 14,359
  • 13
  • 74
  • 124
1

I was using this way:

        worksheet.get_Range(11, 1, 11, 41)
            .SetHeadFontStyle()
            .SetHeadFillStyle(45)
            .SetBorders(
                XlBorderWeight.xlMedium
                , XlBorderWeight.xlThick
                , XlBorderWeight.xlMedium
                , XlBorderWeight.xlThick)
            ;

SetHeadFontStyle / SetHeadFillStyle is ExtMethod of Range like below:

 public static Range SetHeadFillStyle(this Range rng, int colorIndex)
 {
     //do some operation
     return rng;
 }

do some operation and return the Range for next operation

it's look like Linq :)

but now still can't fully look like it -- propery set value

with cell.Border(xlEdgeTop)
   .LineStyle = xlContinuous
   .Weight = xlMedium
   .ColorIndex = xlAutomatic
IlPADlI
  • 1,943
  • 18
  • 22
1

A big fan of With here!

This is literally my current C# code:

if (SKYLib.AccountsPayable.Client.ApiAuthorization.Authorization.AccessTokenExpiry == null || SKYLib.AccountsPayable.Client.ApiAuthorization.Authorization.AccessTokenExpiry < DateTime.Now)
{
    SKYLib.AccountsPayable.Client.ApiAuthorization.Authorization.Refresh();
    _api = new SKYLib.AccountsPayable.Api.DefaultApi(new SKYLib.AccountsPayable.Client.Configuration { DefaultHeader = SKYLib.AccountsPayable.Client.ApiAuthorization.Authorization.ApiHeader });
}

In VB it could be:

With SKYLib.AccountsPayable.Client.ApiAuthorization.Authorization
    If .AccessTokenExpiry Is Nothing OrElse .AccessTokenExpiry < Now Then .Refresh()
    _api = New SKYLib.AccountsPayable.Api.DefaultApi(New SKYLib.AccountsPayable.Client.Configuration With {DefaultHeader = .ApiHeaders}
End With

Much clearer I think. You could even tweak it to be more concise by tuning the With variable. And, style-wise, I still have a choice! Perhaps something the C# Program Manager has overlooked.

As an aside, it's not very common to see this, but I have used it on occasion:

Instead of

Using oClient As HttpClient = New HttpClient
    With oClient
        .BaseAddress = New Uri("http://mysite")
        .Timeout = New TimeSpan(123)
        .PostAsync( ... )
    End With
End Using

You can use

With New HttpClient
    .BaseAddress = New Uri("http://mysite")
    .Timeout = New TimeSpan(123)
    .PostAsync( ... )
End With

You risk a wrist-slapping - as do I for posting! - but it seems that you get all the benefits of a Using statement in terms of disposal, etc without the extra rigmarole.

NOTE: This can go wrong occasionally, so only use it for non-critical code. Or not at all. Remember: You have a choice ...

SteveCinq
  • 1,920
  • 1
  • 17
  • 22
1

To make life a little easier you can use vertical selection to quickly edit things

http://joelabrahamsson.com/select-columns-of-text-in-visual-studio/

Sid
  • 355
  • 1
  • 5
  • 11
0

There is another an interesting implementation of with-pattern

public static T With<T>(this T o, params object[] pattern) => o;
public static T To<T>(this T o, out T x) => x = o;

You may browse more details by the link and research online code samples.

Variations of usage

static Point Sample0() => new Point().To(out var p).With(
    p.X = 123,
    p.Y = 321,
    p.Name = "abc"
);

public static Point GetPoint() => new Point { Name = "Point Name" };
static string NameProperty { get; set; }
static string NameField;

static void Sample1()
{
    string nameLocal;
    GetPoint().To(out var p).With(
        p.X = 123,
        p.Y = 321,
        p.Name.To(out var name), /* right side assignment to the new variable */
        p.Name.To(out nameLocal), /* right side assignment to the declared var */
        NameField = p.Name, /* left side assignment to the declared variable */
        NameProperty = p.Name /* left side assignment to the property */
    );

    Console.WriteLine(name);
    Console.WriteLine(nameLocal);
    Console.WriteLine(NameField);
    Console.WriteLine(NameProperty);
}

static void Sample2() /* non-null propogation sample */
{
    ((Point)null).To(out var p)?.With(
        p.X = 123,
        p.Y = 321,
        p.Name.To(out var name)
    );

    Console.WriteLine("No exception");
}

static void Sample3() /* recursion */
{
    GetPerson().To(out var p).With(
        p.Name.To(out var name),
        p.Subperson.To(out var p0).With(
            p0.Name.To(out var subpersonName0)
        ),
        p.GetSubperson().To(out var p1).With( /* method return */
            p1.Name.To(out var subpersonName1)
        )
    );

    Console.WriteLine(subpersonName0);
    Console.WriteLine(subpersonName1);
}

If you work with structs [value types] the similar extension method will be useful too

public static TR Let<T, TR>(this T o, TR y) => y;

May be applied after With method because by default will be returned the unmodified copy of struct

struct Point
{
    public double X;
    public double Y;
    public string Name;
}

static Point Sample0() => new Point().To(out var p).With(
    p.X = 123,
    p.Y = 321,
    p.Name = "abc"
).Let(p);

Enjoy if you like!

Makeman
  • 884
  • 9
  • 16
  • Interesting. The online code samples that you provide a link to are definitely worth a read. – RichardB Jun 23 '22 at 05:52
  • @RichardB , 'To-With' extensions is an experimental approach which may be useful in some cases. For example during chain type castings: void OnButtonClick(object sender, EventArgs args) => sender.To(out Button b).DataContext.To(out AppViewModel vm).With(vm.Data = b.Tag); – Makeman Jun 25 '22 at 07:47
0

I think the closets thing to "with" is static using, but only works with static's methods or properties. e.g.

using static System.Math;
...
public double Area
{
   get { return PI * Pow(Radius, 2); } // PI == System.Math.PI
}

More Info: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-static

Jaider
  • 14,268
  • 5
  • 75
  • 82
0

For me I was trying to auto generate code, and needed to reuse a simple variable like "x" for multiple different classes so that I didn't have to keep generating new variable names. I found that I could limit the scope of a variable and reuse it multiple times if I just put the code in a curly brace section {}.

See the example:

public class Main
{
    public void Execute()
    {
        // Execute new Foos and new Bars many times with same variable.
        double a = 0;
        double b = 0;
        double c = 0;
        double d = 0;
        double e = 0;
        double f = 0;

        double length = 0;
        double area = 0;
        double size = 0;

        {
            Foo x = new Foo(5, 6).Execute();
            a = x.A;
            b = x.B;
            c = x.C;
            d = x.D;
            e = x.E;
            f = x.F;
        }
        {
            Bar x = new Bar("red", "circle").Execute();
            length = x.Length;
            area = x.Area;
            size = x.Size;
        }
        {
            Foo x = new Foo(3, 10).Execute();
            a = x.A;
            b = x.B;
            c = x.C;
            d = x.D;
            e = x.E;
            f = x.F;
        }
        {
            Bar x = new Bar("blue", "square").Execute();
            length = x.Length;
            area = x.Area;
            size = x.Size;
        }
    }
}

public class Foo
{
    public int X { get; set; }
    public int Y { get; set; }
    public double A { get; private set; }
    public double B { get; private set; }
    public double C { get; private set; }
    public double D { get; private set; }
    public double E { get; private set; }
    public double F { get; private set; }

    public Foo(int x, int y)
    {
        X = x;
        Y = y;
    }

    public Foo Execute()
    {
        A = X * Y;
        B = X + Y;
        C = X / (X + Y + 1);
        D = Y / (X + Y + 1);
        E = (X + Y) / (X + Y + 1);
        F = (Y - X) / (X + Y + 1);
        return this;
    }
}

public class Bar
{
    public string Color { get; set; }
    public string Shape { get; set; }
    public double Size { get; private set; }
    public double Area { get; private set; }
    public double Length { get; private set; }
    
    public Bar(string color, string shape)
    {
        Color = color;
        Shape = shape;
    }

    public Bar Execute()
    {
        Length = Color.Length + Shape.Length;
        Area = Color.Length * Shape.Length;
        Size = Area * Length;
        return this;
    }
}

In VB I would have used the With and not needed variable "x" at all. Excluding the vb class definitions of Foo and Bar, the vb code is:

Public Class Main
    Public Sub Execute()
        Dim a As Double = 0
        Dim b As Double = 0
        Dim c As Double = 0
        Dim d As Double = 0
        Dim e As Double = 0
        Dim f As Double = 0
        Dim length As Double = 0
        Dim area As Double = 0
        Dim size As Double = 0

        With New Foo(5, 6).Execute()
            a = .A
            b = .B
            c = .C
            d = .D
            e = .E
            f = .F
        End With

        With New Bar("red", "circle").Execute()
            length = .Length
            area = .Area
            size = .Size
        End With

        With New Foo(3, 10).Execute()
            a = .A
            b = .B
            c = .C
            d = .D
            e = .E
            f = .F
        End With

        With New Bar("blue", "square").Execute()
            length = .Length
            area = .Area
            size = .Size
        End With
    End Sub
End Class
Jroonk
  • 1,376
  • 1
  • 9
  • 12
0

The shortest possible equivalent for something like

something.A;
something.B;
something.C;
something.D;

is

var _ = something;

_.A;
_.B;
_.C;
_.D;

or enclosed for the scope:

{  var _ = something;

   _.A;
   _.B;
   _.C;
   _.D;
}
-3

If there are multiple levels of objects you can get similar functionality with the "using" directive:

using System;
using GenderType = Hero.GenderType; //This is the shorthand using directive
public partial class Test : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        var myHero = new Hero();
        myHero.Name = "SpamMan";
        myHero.PowerLevel = 3;
        myHero.Gender = GenderType.Male; //instead of myHero.Gender = Hero.GenderType.Male;
    }
}
public class Hero
{
    public enum GenderType
    {
        Male,
        Female,
        Other
    }
    public string Name;
    public int PowerLevel;
    public GenderType Gender;
}
Bolo
  • 1,494
  • 1
  • 19
  • 19
-3

hmm. I have never used VB.net in any depth, so I'm making an assumption here, but I think the 'using' block might be close to what you want.

using defines a block scope for a variable, see the example below

using ( int temp = someFunction(param1) ) {
   temp++;  // this works fine
}

temp++; // this blows up as temp is out of scope here and has been disposed

Here is an article from Microsoft that explains a bit more


EDIT: yeah, this answer is wrong - the original assumption was incorrect. VB's 'WITH' is more like the new C# object initialisers:

var yourVariable = new yourObject { param1 = 20, param2 = "some string" };
mlennox
  • 122
  • 4
  • No, a using statement is very different - the point of a using statement is to dispose of a resource at the end of the block. It doesn't make referring to the value any shorter. – Jon Skeet Jan 26 '09 at 23:46
  • Thanks Jon, always good to learn something new about another language, I suppose I should have taken heed of the old statement "Assume makes an ass out of u and me" - but I guess its only me looking bad in this case ;) – mlennox Jan 26 '09 at 23:57
  • 2
    nope ... the initializer only works on initialization ... have a look at fluent interfaces! –  Jan 28 '09 at 07:09
  • There is no reason `using` couldn't make referring to the value shorter (borrowing from an answer above): `using (var c=cell.Border(xlEdgeTop)) { c.LineStyle = xlContinuous; c.Weight = xlMedium; c.ColorIndex = xlAutomatic; }` – NetMage Nov 10 '16 at 22:26