views:

314

answers:

10

For the hardcore C# coders here, this might seem like a completely stupid question - however, I just came across a snippet of sample code in the AWS SDK forum and was completely sideswiped by it:

   RunInstancesRequest runInstance = new RunInstancesRequest()
    .WithMinCount(1)
    .WithMaxCount(1)
    .WithImageId(GetXMLElement("ami"))
    .WithInstanceType("t1.micro");

This is very reminiscent of the old VB6 With ... End With syntax, which I have long lamented the absence of in C# - I've compiled it in my VS2008 project and it works a treat, saving numerous separate lines referencing these attributes individually.

I'm sure I've read articles in the past explaining why the VB6-style With-block wasn't in C#, so my question is: has this syntax always existed in the language, or is it a recent .NET change that has enabled it? Can we coat all object instantiations followed by attribute changes in the same sugar?

+4  A: 

It is not syntactic sugar. Those methods just set a property and return the this object.

klausbyskov
A: 

This syntax has always existed

Armen Tsirunyan
+14  A: 

They implemented all those methods, each of which will also be returning the RunInstancesRequest object (aka, this). It's called a Fluent Interface

Chad
Nice link. I like this example: http://en.wikipedia.org/wiki/Fluent_interface#C.23
Michael Levy
+19  A: 

Isn't this better anyway?

RunInstancesRequest runInstance = new RunInstancesRequest 
{
    MinCount = 1, 
    MaxCount = 1, 
    ImageId = GetXMLEleemnt("ami"), 
    InstanceType = "t1.micro"
};
Kirk Woll
+1 I love learning new things.
Brad
I agree, for setting properties/constructors, this is a better syntax. But in scenarios where you are working with an existing item, and will often be modifying several properties, or calling several methods in a chain, fluent interfaces shine. It's one of the many reasons jQuery is so nice to work with.
Chad
And you can't use it on an immutable object. Personally I think this syntax should only be used if the original object isn't modified(like in Linq).
CodeInChaos
@CodeInChaos, well, you can't use immutable *classes* (as opposed to structs) with a fluent interface either unless you want to instantiate a *ton* of spurious objects.
Kirk Woll
It's one additional object per step. And I'm pretty sure Linq creates one instance which implements IEnumerable per step on query creation. And one IEnumerator per step on query evaluation. I don't think the spurious objects matter much since they'll probably get collected in the generation 0 GC.
CodeInChaos
@CodeInChaos, it's reasonable to instantiate objects and assign the properties in the midst of a big for-loop. It's not so reasonable to perform IEnumerable operations in the midst of that same loop. Therefore IMO, it's OK for IEnumerable to be somewhat expensive per operation, less so for plain vanilla property assignment.
Kirk Woll
+1  A: 

The reason this syntax works for RunInstancesRequest is that each of the method calls that you are making return the original instance. The same concept can be applied to StringBuilder for the same reason, but not all classes have methods implemented in this way.

Mark Avenius
+3  A: 

I think this technique is different than the With... syntax in VB. I think this is an example of chaining. Each method returns an instance of itself so you can chain the method calls.

See http://stackoverflow.com/questions/1119799/method-chaining-in-c

Michael Levy
+1  A: 

I would prefer having a constructor that takes all of those property values as arguments and sets them within the class.

Bernard
+1. I dislike anything that lets partially-constructed classes live. I just about put up with it for LINQ2SQL or other ORMs as an artefact of OO-ORM impedance, but there's no justification most of the time. Doesn't mean it can't be used along-side proper constructors and class invariants, but I can see how this would encourage breaking away from that.
Jon Hanna
+3  A: 
RunInstancesRequest runInstance = new RunInstancesRequest()
.WithMinCount(1)
.WithMaxCount(1)
.WithImageId(GetXMLElement("ami"))
.WithInstanceType("t1.micro");

==

RunInstancesRequest runInstance = new RunInstancesRequest().WithMinCount(1).WithMaxCount(1).WithImageId(GetXMLElement("ami")).WithInstanceType("t1.micro");

I don't know if that's considered syntactic sugar, or just pure formatting.

ManAmongHippos
+1: the whitespace around the `.` is (and always has been) completely ignored by the compiler.
Hans Kesting
+1  A: 

It's always existed in C# and indeed in any C-style oo language (eh, most popular C-style language except C itself!)

It's unfair to compare it the the VB6 With...End With syntax, as it's much clearer what is going on in this case (about the only good thing I have to say about VB6's With...End With is at least it isn't as bad as Javascripts since it requires prior dots).

It is as people have said, a combination of the "fluent interface" and the fact that the . operator allows for whitespace before and after it, so we can put each item on newlines.

StringBuilder is the most commonly seen case in C#, as in:

new StringBuilder("This")
  .Append(' ')
  .Append("will")
  .Append(' ')
  .Append("work")
  .Append('.');

A related, but not entirely the same, pattern is where you chain the methods of an immutable object that returns a different object of the same type as in:

DateTime yearAndADay = DateTime.UtcNow.AddYears(1).AddDays(1);

Yet another is returning modified IEnumerable<T> and IQueryable<T> objects from the LINQ related methods.

These though differ in returning different objects, rather than modifying a mutable object and returning that same object.

One of the main reasons that it is more common in C++ and Java than in C# is that C# has properties. This makes the most idiomatic means of assigning different properties a call to the related setter that is syntactically the same as setting a field. It does however block much of the most common use of the fluent interface idiom.

Personally, since the fluent interface idiom is not guaranteed (there's nothing to say MyClass.setProp(32) should return this or indeed, that it shouldn't return 32 which would also be useful in some cases), and since it is not as idiomatic in C#, I prefer to avoid it apart from with StringBuilder, which is such a well-know example that it almost exists as a separate StringBuilder idiom within C#

Jon Hanna
A: 

Please refer to Extension Methods (C# Programming Guide)

Salizar Marxx