Priority
Normal
Type
Usability Problem 
State
Submitted 
Assignee
Andrew Koryavchenko 
Subsystem
No subsystem 
Affected versions
Fix for
  • Submitted by   Peter Mounce
    19 months ago (10 Dec 2008 23:35)
  • Updated by   Peter Mounce
    8 months ago (30 Nov 2009 00:07)
  • Jira: RSRP-88220
    (history, comments)
RSRP-88220 Formatting fluent interface & lambda C#
6
I'm writing quite a lot of code that makes use of fluent interfaces. For example, Rhino Mocks looks like:
mockCrypto.Expect(c => c.Hash("authenticationHashSalt", "ignoring arguments")).IgnoreArguments().Return("hashed");


I would prefer that to reformat to:
mockCrypto.Expect(c => c.Hash("authenticationHashSalt", "ignoring arguments"))
    .IgnoreArguments()
    .Return("hashed");

(where the indent is a single tab).

For LINQ queries, same thing. I'd like each fluent call to be one a new line, indented and aligned.
Comments (6)
 
History
 
Linked Issues (2)
 
TeamCity Changes (0)
 
Steve Wagner
  Steve Wagner
21 Apr 2009 14:20
(15 months ago)
I also think that this is a huge problem. With my current settings ReSharper dose the following formatting and this is hard to read:

Orders = accountContext.Orders.OrderBy( o => o.Description ).Select(
o => viewModelFactory.Create<SearchOrderViewModel>( o ) ).ToArray();


ReSharper needs an option to order each function ind a function calling pipe to be ordered on a single line. Example:

Orders = accountContext.Orders.OrderBy( o => o.Description )
.Select(o => viewModelFactory.Create<SearchOrderViewModel>( o ) )
.ToArray();
Steve Wagner
  Steve Wagner
21 Apr 2009 14:43
(15 months ago)
The most time this is more problematic if "Keep existing line breaks" is disabled.
Lionel Guilhou
  Lionel Guilhou
18 Nov 2009 21:07
(8 months ago)
One more voice on this issue, since I'm in the middle of writing some Fluent NHibernate mappings :)

Same problem, I'm getting
new PersistenceSpecification<Movie>(Session).CheckProperty(x => x.Article, "The").CheckProperty(
	x => x.Title, "Title").CheckReference(x => x.Type, type).CheckEnumerable(
	x => x.Regions, (a, b) => a.AddRegion(b), regions).CheckEnumerable(
	x => x.Genres, (a, b) => a.AddGenre(b), genres).VerifyTheMappings();
which is pretty much unreadable, while an option to add a line break in a function call chain could give
new PersistenceSpecification<Movie>(Session)
	.CheckProperty(x => x.Article, "The")
	.CheckProperty(x => x.Title, "Title")
	.CheckReference(x => x.Type, type)
	.CheckEnumerable(x => x.Regions, (a, b) => a.AddRegion(b), regions)
	.CheckEnumerable(x => x.Genres, (a, b) => a.AddGenre(b), genres)
	.VerifyTheMappings();


Enforcing a line break starting at, say, the second method call would probably be quite sufficient for fluent interfaces, though it would also enforce it for 'standard' code using smaller call chains.
Personally, I wouldn't mind that since it would help to highlight problems (excessive violations of the law of demeter, need to introduce variables to make the code more readable, ...)

Alternatively, it could be a 'Chop always' extension to the current line wrapping option, in the same spirit as the options for formal parameters and invocation arguments. If the line is too long, it chops it before each '.'

Enabling 'Keep existing line breaks' is a workaround to do this manually, but it also makes regular reformatting much more tedious.
Joel Mueller
  Joel Mueller
29 Nov 2009 23:25
(8 months ago)
I do not agree that 99007 is a duplicate of this issue, although they are related. This issue is about where the auto-formatting inserts line breaks when dealing with chained method calls, while 99007 is about how far to indent chained method calls. Specifically, the "single tab stop" requested in this issue is exactly the opposite of what is being requested in 99007.
Peter Mounce
  Peter Mounce
29 Nov 2009 23:41
(8 months ago)
I don't think this is a duplicate of 99007 either.
Lionel Guilhou
  Lionel Guilhou
30 Nov 2009 00:07
(8 months ago)
Yup, not exactly the same thing, though #88220 would have to be resolved before #99007 could be addressed.

Also, #99007 does duplicate #88220 in one particular case: the 'chop always/chop if long' option. If the method chain is chopped starting at the first period, all calls would be aligned on the same column:
public int After
{
    get
    {
        return _visitors
            .Where(v => v.RowsWritten != 0)
            .Select(v => v.RowsWritten)
            .FirstOrDefault();
    }
}
Not exactly the suggested formatting in #99007, but close. Additionally, being able to align under the initial object in the chain + 1 tab indent would give:
public int After
{
→get
→{
→→return _visitors
→→- - - - - - - →.Where(v => v.RowsWritten != 0)
→→- - - - - - - →.Select(v => v.RowsWritten)
→→- - - - - - - →.FirstOrDefault();
→}
}

This seems to be the real difference between those issues.