What is the ampersand character at the end of an object type?
Asked Answered
T

2

15

I had to de-compile some code and I don't know what this syntax is? Can y'all help, or point me to a write-up about what it is? I've Googled and searched this site and can't find anything.

Just one line of code:

Rectangle pageBounds;
// ISSUE: explicit reference operation
// ISSUE: variable of a reference type
Rectangle& local = @pageBounds;

What is the @ symbol at the end of the Rectangle object type, and the @ before the pageBounds variable?

This is my last line of code that I need to fix in order to get this executable to compile again.

Here's the method that uses this syntax, can I get away with removing it?

protected override void OnPrintPage(PrintPageEventArgs e)
{
  Application.DoEvents();
  ++this._pageNum;
  float num1;
  if (this.Header != null)
  {
    num1 = this.Header.CalculateHeight(this, e.Graphics);
    this.Header.Draw(this, (float) e.MarginBounds.Top, e.Graphics, e.MarginBounds);
  }
  else
    num1 = 0.0f;
  float num2;
  if (this.Footer != null)
  {
    num2 = this.Footer.CalculateHeight(this, e.Graphics);
    this.Footer.Draw(this, (float) e.MarginBounds.Bottom - num2, e.Graphics, e.MarginBounds);
  }
  else
    num2 = 0.0f;
  Rectangle pageBounds;
  // ISSUE: explicit reference operation
  // ISSUE: variable of a reference type
  Rectangle& local = @pageBounds;
  int left = e.MarginBounds.Left;
  Rectangle marginBounds = e.MarginBounds;
  int y = (int) ((double) marginBounds.Top + (double) num1);
  marginBounds = e.MarginBounds;
  int width = marginBounds.Width;
  marginBounds = e.MarginBounds;
  int height = (int) ((double) marginBounds.Height - (double) num2 - (double) num1);
  // ISSUE: explicit reference operation
  local = new Rectangle(left, y, width, height);
  float yPos = (float) pageBounds.Top;
  bool flag = false;
  int num3 = 0;
  while (this._printIndex < this._printElements.Count)
  {
    PrintElement printElement = (PrintElement) this._printElements[this._printIndex];
    float num4 = printElement.CalculateHeight(this, e.Graphics);
    if ((double) yPos + (double) num4 > (double) pageBounds.Bottom && num3 != 0)
    {
      flag = true;
      break;
    }
    else
    {
      printElement.Draw(this, yPos, e.Graphics, pageBounds);
      yPos += num4;
      ++this._printIndex;
      ++num3;
    }
  }
  e.HasMorePages = flag;
}
Traitor answered 16/6, 2012 at 22:5 Comment(5)
Read up on references and pointersMechellemechlin
@MichaelDibbets: This is C#...Accustom
C# has references, pointers, and value types ;)Adz
Confused re title and body... the & is the "ampersand" (title), the @ is "at" (body) - which are you asking about?Trilobate
@MarcGravell actually, both. Should change my title...Traitor
T
28

The comments right before that line of code are telling you exactly what's going on. The & after a type name indicates that it's a reference type, and the @ before a variable name generates a reference to that variable.

(The @ sign can also be used in C# code to escape keywords for use as variable names but that's not what is happening here. pageBounds is not a C# keyword.)

Note that this is not valid C# syntax -- you cannot take a reference to a local variable in C#, although the CLR supports it. (NOTE: As of C# 7.0, this is no longer true; the syntax is described here, but it does not use the & so this decompiled code is still invalid C#).

Creating a reference to a local variable happens implicitly when you use ref and out parameters, for example, but the keywords are used instead of explicitly typing the parameters as reference. (e.g. if you had an out int x, internally that variable is of type Int32&.) The intent of the code, if it were legal C#, would be that pageBounds and local were the same instance with two different names; anything you do to one happens to the other. So, for example, this illegal code:

Rectangle pageBounds;
Rectangle& local = @pageBounds;
local = new Rectangle();

would be the same as this legal code:

Rectangle pageBounds = new Rectangle();

If you tried to compile the code as-decompiled, you would get an error because the compiler treats & as the bitwise and operator, and will complain that you used a type as if it were a variable. But that's ok because you didn't get it from a C# source file. You decompiled an IL method to get it, and there are a lot of things you can do in IL that are illegal in C#. This happens all the time when you decompile code; you see illegal class and method names for example. It just means that the compiler generated IL based on the original code that does not translate directly back into C#, but behaves the way you wanted. The code you are getting back is simply the decompiler's best attempt to produce C# code from the IL it has.

You can see examples of the sort of code that produces these references in the numerous Jetbrains bug reports about them:

Ti answered 16/6, 2012 at 22:49 Comment(3)
fantastic answer. Thank you for the explanation, it kind of makes sense now. For my situation, is it as easy as removing both of those extra characters to make the code work (and set the Rectangle x = new Rectangle();)?Traitor
to be honest, I can't see any reason you need the local variable at all; its only being used to construct pageBounds by reference. I suspect it was a compiler optimization that is confusing the decompiler. Just eliminate local and construct a new pageBounds directly.Ti
really appreciate it Michael!Traitor
M
4

See Here - http://msdn.microsoft.com/en-us/library/aa664670(v=vs.71).aspx (Have never used though)

The prefix "@" enables the use of keywords as identifiers, which is useful when interfacing with other programming languages. The character @ is not actually part of the identifier, so the identifier might be seen in other languages as a normal identifier, without the prefix. An identifier with an @ prefix is called a verbatim identifier. Use of the @ prefix for identifiers that are not keywords is permitted, but strongly discouraged as a matter of style.

The example:

class @class
{
   public static void @static(bool @bool) {
      if (@bool)
         System.Console.WriteLine("true");
      else
         System.Console.WriteLine("false");
   }   
}
class Class1
{
   static void M() {
      cl\u0061ss.st\u0061tic(true);
   }
}
Monochromat answered 16/6, 2012 at 22:11 Comment(2)
Please writenthe reason before downvoting. Have some real guts !Monochromat
Thanks for this explanation. Your link is not working anymore, I think. Here is the explanation (see point 3): learn.microsoft.com/en-us/dotnet/csharp/language-reference/…Rugose

© 2022 - 2024 — McMap. All rights reserved.