Skip to main content

How to Resolve Error "CS0071: An explicit interface implementation of an event must use event accessor syntax" in C#

The Compiler Error CS0071 is a syntax error related to Explicit Interface Implementation. The message reads: "An explicit interface implementation of an event must use event accessor syntax".

In C#, you usually declare events using "field-like" syntax (e.g., public event EventHandler MyEvent;). The compiler automatically generates the add/remove methods and a private backing field for you. However, when you implement an event explicitly (prefixing it with the interface name to hide it from the public API), the compiler refuses to generate this automatic logic. You are required to write the add and remove accessors and manage the backing delegate manually.

This guide explains how to correctly implement interface events explicitly.

Understanding Explicit Implementation

Explicit interface implementation is used when:

  1. A class implements two interfaces that have a member with the same name.
  2. You want to hide a member from the class's public surface, making it accessible only when casting the object to the interface.

For methods, it looks like this: void IMyInterface.Method() { ... }. For events, the syntax requires more detail because the compiler disables the "syntactic sugar" that normally handles event subscription storage.

Scenario: The Invalid Short Syntax

You define an interface with an event, and try to implement it explicitly using the standard, short declaration style.

Example of error:

using System;

public interface IProcess
{
event EventHandler OnCompleted;
}

public class Worker : IProcess
{
// ⛔️ Error CS0071: An explicit interface implementation of an event
// must use event accessor syntax.
// The compiler cannot auto-generate the backing field for an explicit member.
event EventHandler IProcess.OnCompleted;
}

Solution: Implementing Manual Accessors

To fix this, you must:

  1. Define a private delegate field to store the subscribers.
  2. Implement the event using the explicit name.
  3. Add add and remove blocks to manage the subscription list manually.

Correct Implementation:

using System;

public interface IProcess
{
event EventHandler OnCompleted;
}

public class Worker : IProcess
{
// 1. Create a private backing field to store the delegates
private EventHandler _onCompletedDelegate;

// 2. Implement the interface event explicitly with accessors
// ✅ Correct: We define exactly what happens when someone subscribes.
event EventHandler IProcess.OnCompleted
{
add
{
// Add the subscriber to our private field
_onCompletedDelegate += value;
}
remove
{
// Remove the subscriber
_onCompletedDelegate -= value;
}
}

public void DoWork()
{
Console.WriteLine("Working...");

// 3. Invoke the event using the private field
_onCompletedDelegate?.Invoke(this, EventArgs.Empty);
}
}

public class Program
{
static void Main()
{
Worker w = new Worker();

// w.OnCompleted += ... // Error: Not visible on the class directly

// Casting to the interface to access the event
IProcess p = w;
p.OnCompleted += (s, e) => Console.WriteLine("Done!");

w.DoWork();
}
}

Output:

Working...
Done!
note

Why is this required? When you use the short syntax (public event X;), the compiler generates a field with the same name. But for IProcess.OnCompleted, the name contains a dot, which is invalid for a field name. Therefore, the compiler forces you to define your own storage mechanism.

Conclusion

CS0071 is the compiler forcing you to be verbose because it cannot automate the backing logic for explicit members.

  1. Declare a private field: You need a place to store the subscriptions (e.g., private EventHandler _myEvent;).
  2. Write the accessors: Use the { add { ... } remove { ... } } syntax.
  3. Use value: Inside the accessors, the keyword value represents the delegate being added or removed.