Search code examples
c#pass-by-referencebitwise-operators

How to refactor this decompiled C# code with invalid reference syntax?


After decompiling an assembly, the code it generated resulted in a lot of methods similar to this:

internal long m_position;

internal void PutString(long RecordNumber, string s)
{
    if (s == null)
        s = "";
    int byteCount = this.m_Encoding.GetByteCount(s);
    this.SetRecord(RecordNumber);
    this.LengthCheck(byteCount);
    if (byteCount != 0)
        this.m_sw.Write(s);
    // ISSUE: variable of a reference type
    long& local;
    // ISSUE: explicit reference operation
    long num = checked (^(local = ref this.m_position) + (long) byteCount);
    local = num;
}

It's only the code starting at // ISSUE that's having a problem. As you can see, it contains invalid syntax long& local;. I found this answer which does a great job of explaining what this is. After reading up on C# ref locals, I tried to refactor this method so that it can compile, but I haven't been successful. The ^(local = ref this.m_position) part really does me in, as I'm not very strong when it comes to bitwise operations.

Could someone help me refactor those last three lines and explain to me how it works? This pattern appears almost verbatim in the decompiled code hundreds of times, so once I "grok" this one example, I should have no problem with the rest of it.


Solution

  • This is one of those things that dotPeek fails on but ILSpy handles nicely. What you're seeing is a compiler optimization of the += operator. Rather than calculate the field location twice - once to fetch the value and again to store it - the compiler generates code that calculates the field offset one time then uses it for both parts of the operation.

    The bit you're having trouble with (the unknown ^ operator) is most likely an attempt by dotPeek to show a dereference of the ref variable. Of course this isn't necessary in C# where we just use the name of the variable itself.

    Just rewrite it as:

    m_position += byteCount;
    

    The compiler will decide whether or not it wants to add that particular optimization in.