C Sharp

What the Compiler Is Really Doing

So, how does the compiler allow us to call a method in the standard object.field syntax? Also, where does that value variable come from? To answer these questions, we need to look at the MSIL being produced by the compiler. Let's consider the property's getter method first.

In our ongoing example, we have the following getter method defined: -

class Address
{
    protected string city;
    protected string zipCode;
    public string ZipCode
    {
        get
        {
            return zipCode;
        }
        image
    }
    image
}

If you look at the resulting MSIL from this method, you'll see that the compiler has created an accessor method called get_ZipCode, as seen here: -

.method public hidebysig specialname instance string
        get_ZipCode() cil managed
{
  // Code size       11 (0xb)
  .maxstack  1
  .locals ([0] string _Vb_t_$00000003$00000000)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      string Address::zipCode
  IL_0006:  stloc.0
  IL_0007:  br.s       IL_0009
  IL_0009:  ldloc.0
  IL_000a:  ret
} // end of method Address::get_ZipCode

You can tell the name of the accessor method because the compiler prefixes the property name with get_ (for a getter method) or set_ (for a setter method). As a result, the following code resolves to a call to get_ZipCode: -

String str = addr.ZipCode; // this calls Address::get_ZipCode

Therefore, you might be tempted to try the following explicit call to the accessor method yourself: -

String str = addr.get_ZipCode; // **ERROR " Won't compile

However, in this case, the code will not compile because it's illegal to explicitly call an internal MSIL method.

The answer to our question-how can a compiler allow us to use the standard object.field syntax and have a method be called?-is that the compiler actually generates the appropriate getter and setter methods for us when it parses the C# property syntax. Therefore, in the case of the Address.ZipCode property, the compiler emits MSIL that contains the get_ZipCode and set_ZipCode methods.

Now let's look at the generated setter method. In the Address class you saw the following: -

    public string ZipCode
    {
        image
        set
        {
            // Validate value against some datastore.
            zipCode = value;
           // Update city based on validated zipCode.
        }
    }

Notice that nothing in this code declares a variable named value yet we're able to use this variable to store the caller's passed value and to set the protected zipCode member field. When the C# compiler generates the MSIL for a setter method, it injects this variable as an argument in a method called set_ZipCode.

In the generated MSIL, this method takes as an argument a string variable: -

.method public hidebysig specialname instance void
        set_ZipCode(string 'value') cil managed
{
  // Code size       8 (0x8)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  stfld      string Address::zipCode
  IL_0007:  ret
} // end of method Address::set_ZipCode

Even though you can't see this method in the C# source code, when you set the ZipCode property with something like addr.ZipCode("12345"), it resolves to an MSIL call to Address::set_ZipCode("12345"). As with the get_ZipCode method, attempting to call this method directly in C# generates an error.