10

So, if I execute the following code...

int x = 0;
Debug.WriteLine(x++);
Debug.WriteLine(x += 4);
Debug.WriteLine(x);

... I get 0, 5, and 5, respectively. What I'd like to get, however is 0, 1, and 5. Is there any way to do a post-increment by n in C#? Or do I have to write out the += as its own statement?

Just for context, what I'm actually doing is a bunch of BitConverter operations on a buffer, and it'd be really nice to have each one as a self-sufficient statement where the offset is incremented by the size of the data type being converted to. That way, if the buffer format is later changed, I can just add or remove the one line without having to worry about any of the surrounding code.

3 Answers3

5

You should be able to abuse Interlocked.Exchange to get the old value of a variable while at the same time replacing its value:

Debug.WriteLine(Interlocked.Exchange(ref x, x+4));

in other words, replace the value of variable x with x + 4 but return the previous value of x.

Edit:

Disassembly shows this "increment by 4 and swap" is done in 4 instructions - no call needed at all, so performance should be good:

            Interlocked.Exchange(ref x, x + 4);
0000005e  mov         eax,dword ptr [rbp+2Ch] 
00000061  add         eax,4 
00000064  xchg        eax,dword ptr [rbp+2Ch] 
00000067  mov         dword ptr [rbp+28h],eax 

The non-intuitive nature of this (and other) solutions probably boils down to the violation of the CQS principle - we are mutating a variable and returning a value all at once, i.e. not something we should be doing in the mainstream.

StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • This is very nice as well. Not intuitive, IMHO: you should spin a bit of brain in order to understand what the purpose of the line. – Mario Vernari Dec 09 '13 at 05:19
  • 1
    And I just learned something new. I'll give it a try and see how it performs compared to just using x += 4 as a separate operation. After all, I can always write that as a statement at the end of the line and tell StyleCop what to go do with itself when it complains about multiple statements on one line. :) This is basically the heart of a long-running operation, though, so whatever's fastest wins! –  Dec 09 '13 at 05:28
  • 1
    Just tested it and the performance was on par with writing a custom function, but not surprisingly, slower than just adding the extra x += 4. –  Dec 09 '13 at 05:42
  • Interlocked operations are potentially far more expensive than needed here. Furthermore, they only work when one argument is a memory location. In code like this, `x` ought to be in a register. Not all 4 instruction sequences are created equal. I'd venture to guess the performance approaches a custom function only if that function doesn't get inlined. – Ben Voigt Dec 29 '13 at 03:53
  • If you're going to call a method somewhere to do this job, I would rather go the route of creating a specialized method for this with a proper name. – Lasse V. Karlsen Dec 30 '13 at 22:09
4

As far as I know it's not possible. You could write your wrapper method like that:

static void ExecuteWithPost(ref int value, Action<int> operation, Func<int, int> postOperation)
{
    operation(value);
    value = postOperation(value);
}

and use it:

int i = 0;
ExecuteWithPost(ref i, x => Debug.WriteLine(x), x => x + 1);
ExecuteWithPost(ref i, x => Debug.WriteLine(x), x => x + 4);
ExecuteWithPost(ref i, x => Debug.WriteLine(x), x => x);

Prints what you want.

The wrapper method can be generic to make it work with types other than int:

static void ExecuteWithPost<T>(ref T value, Action<T> operation, Func<T, T> postOperation)
{
    operation(value);
    value = postOperation(value);
}
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
  • An upvote by me: I'd write something like this. I only don't like the "ref", and I'd prefer to return the updated value. Just tastes, though. – Mario Vernari Dec 09 '13 at 05:15
  • I thought of doing something like that, but figured it would probably add too much overhead. I like your solution, though, a lot more generic and elegant than mine would have been! –  Dec 09 '13 at 05:15
0

Operator ++ is short form of x = x + 1; so using += is not a bad idea:

If I understand you correctly:

int x = 0;
Debug.WriteLine(x++);  //return 0
Debug.WriteLine(x);  //return 1
Debug.WriteLine(x += 4);  //return 5

I would suggest you to use operator += because any other way operator overloading or something else; will just be a overhead.

Zaheer Ahmed
  • 28,160
  • 11
  • 74
  • 110