简体   繁体   中英

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.

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.

long& represents a reference type for a long and should be replaced with ref long . It's then assigning the address of the m_position field to the local variable (making local an alias for it), then checking for arithmetic overflow when adding the byte count to it. Not entirely sure about the caret, in managed C++ it's a hat to instruct for GC of object, so I suppose that's what it's doing. When the arithmetic check completes successfully, the m_position field via local var is set to the current value plus byteCount .

ref long local = ref this.m_position;
long num = checked(local + (long)byteCount);
local = num;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM