Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the backing field of a compiler generated event always guaranteed to use the same name as the event?

C# allows us to create custom event accessors.

Action _custom;
public event Action Custom
{
    add { _custom = (Action)Delegate.Combine( _custom, value ); }
    remove { _custom = (Action)Delegate.Remove( _custom, value ); }
}

If you don't specify them, the compiler creates them for you. C# language spec:

When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field.

The decompiled source code using dotPeek for a simple public event Action Public; looks as follows:

  private Action Public;

  public event Action Public
  {
    add
    {
      Action action = this.Public;
      Action comparand;
      do
      {
        comparand = action;
        action = Interlocked.CompareExchange<Action>(
                     ref this.Public, comparand + value, comparand);
      }
      while (action != comparand);
    }
    remove
    {
      Action action = this.Public;
      Action comparand;
      do
      {
        comparand = action;
        action = Interlocked.CompareExchange<Action>(
                    ref this.Public, comparand - value, comparand);
      }
      while (action != comparand);
    }
  }

Noteworthy is that the field and the event use the same name. This has led some people to conclude that you can find information about the backing field during reflection by looking up the field in the class with the same name as the event. I implemented this as follows:

public static FieldInfo GetFieldInfo( this EventInfo eventInfo )
{
    Contract.Requires( eventInfo != null );

    return eventInfo.DeclaringType.GetField(
        eventInfo.Name,
        BindingFlags.DeclaredOnly | BindingFlags.Instance |
            BindingFlags.Public | BindingFlags.NonPublic );
}

This works, but raises the question: Is the backing field of a compiler generated event always guaranteed to use the same name as the event?

It's not possible to create custom event accessors which access a delegate with the same name using Visual Studio. This results in the message: "Member with the same name is already declared." I am wondering whether you could conclude that any event for which no backing delegate with the same name is available is an event with custom accessors.

like image 695
Steven Jeuris Avatar asked Mar 23 '12 22:03

Steven Jeuris


People also ask

What is backing field in C#?

A private field that stores the data exposed by a public property is called a backing store or backing field. Fields typically store the data that must be accessible to more than one type method and must be stored for longer than the lifetime of any single method.

What are the backing fields in the Entity Framework?

Backing fields allow EF to read and/or write to a field rather than a property.


2 Answers

Is the backing field of a compiler generated event always guaranteed to use the same name as the event?

Jon and Marc are entirely correct to answer "No".

This is an undocumented implementation detail of the compiler, explicitly noted by the specification as such, and subject to change at any time.

In practice, this is unlikely to change. We use the fact that the field and the event have the same name as the simplest possible way to associate them logically with each other in the compiler.

It's not possible to create custom event accessors which access a delegate with the same name using Visual Studio. This results in the message: "Member with the same name is already declared."

Correct.

I am wondering whether you could conclude that any event for which no backing delegate with the same name is available is an event with custom accessors.

I would not be comfortable making such a conclusion. You might be able to make that conclusion if you knew that the assembly in question had been emitted from the C# compiler. But we are not the only game in town when it comes to emitting assemblies. You can do some pretty weird stuff with ILDASM.

Can I ask why you want to know this stuff? I agree with Marc; if you are accessing a field via Reflection, you're probably doing it wrong. You should be able to access the field within the class no problem (because it is just a private field) and from outside the class, you have no business looking at the private implementation details of another class. It is particularly egregious to use reflection to do an end-run around the thread safety imposed by the accessors. Those accessors are there for your protection; don't run around them.

like image 164
Eric Lippert Avatar answered Oct 17 '22 04:10

Eric Lippert


No - from the C# 4 spec (section 10.8.1):

Within the class X, references to Ev are compiled to reference the hidden field _Ev instead. The name “_Ev” is arbitrary; the hidden field could have any name or no name at all.

So while source-code compatibility is guaranteed, there's no guarantee about the name of the generated field. (In practice, I wouldn't expect this to change any time soon in the MS compiler - but it's not guaranteed, so you shouldn't make assumptions.)

like image 44
Jon Skeet Avatar answered Oct 17 '22 05:10

Jon Skeet