AlgoMaster Logo

Explicit Interface Implementation

Last Updated: May 22, 2026

Medium Priority
10 min read

Most of the time, when a class implements an interface, the interface methods become regular public methods on the class. That is called implicit implementation. C# offers a second form, explicit implementation, where a method belongs to the interface but is hidden from the class's own public surface. This chapter covers the syntax, the three situations where explicit implementation fits, and the rules for using it correctly.

Implicit vs Explicit: The Two Forms

A class that implements an interface can satisfy each member in one of two ways. The implicit form is the familiar one: the method is declared public on the class and counts as the interface implementation automatically. The explicit form qualifies the method with the interface name and removes it from the class's public surface, leaving it visible only through an interface reference.

Two classes, same interface, two different ways of satisfying it. With ProductImplicit, Apply is just a public method that happens to match the interface contract. You can call it directly on the class instance. With ProductExplicit, Apply exists only as part of the interface; the class instance itself doesn't expose it. To invoke it, you either cast to IDiscountable or store the object in a variable typed as the interface.

The key thing to notice about the explicit syntax: no public, no private, no access modifier of any kind. The method is qualified by the interface name (IDiscountable.Apply) and that qualification is what marks it as the explicit implementation.

AspectImplicitExplicit
Syntaxpublic void Apply()void IDiscountable.Apply()
Access modifierRequired (public)Not allowed
Callable on class instanceYesNo
Callable through interface referenceYesYes
Shows up in class's IntelliSenseYesNo

The Syntax Up Close

The explicit form has three rules worth pinning down because the compiler is strict about all of them.

Rule 1: Qualify the member with the interface name. The method name in the declaration is InterfaceName.MemberName, not just MemberName. Drop the qualifier and the compiler treats it as a regular class method, not an explicit implementation.

Rule 2: No access modifier. Explicit members are always accessed through the interface, and interface members are public from the interface's point of view. C# enforces this by refusing any modifier on the declaration.

Rule 3: The interface must actually declare the member. Trying to explicitly implement a method that the interface doesn't have is a compile error.

The CS0539 error message makes the problem obvious once you know to look for it. IRefundable has no Cancel, so claiming to explicitly implement IRefundable.Cancel makes no sense.

One more error code that shows up often: CS0540 fires when the class isn't in the interface's implementation list at all. You can't write void IRefundable.Refund() inside a class that doesn't declare : IRefundable in its header.

These two error codes (CS0539 for non-existent member and CS0540 for non-implementer) are the canonical compile-time failures for explicit implementation. Seeing one of them usually means a missing interface declaration in the class header or a typo in the member name.

Why Use Explicit Implementation

The syntax is one thing. The reason to use it is what matters. Three situations make explicit implementation the right fit.

Reason 1: Two Interfaces Declare the Same Member with Different Intent

The most common driver. A class implements two interfaces that both declare a method named Apply but mean completely different things by it. With implicit implementation alone, there's only one body, so both interfaces share it. That's wrong when the intent differs.

The same object exposes two different Apply methods, one for each interface. Calling Apply on a discount-typed reference runs the discount body; calling it on a refund-typed reference runs the refund body. Neither method clutters the class's own public surface, so item.Apply() doesn't compile at all (the compiler doesn't know which one you'd mean).

A diagram of the same class seen through different interface lenses:

The diagram shows three views of one object. Two of them (the interface views) reach distinct method bodies; the third (the class view) has no Apply at all. The runtime always uses the underlying object, but the path you take to it determines which body runs.

Reason 2: Hide an Interface Member from the Class's Public API

Sometimes you want a class to implement an interface for compatibility, but you don't want the interface's members to clutter the class's own public surface. The base class library does this a lot. Many IList<T> and IEnumerable<T> implementations expose only the generic versions on the class and tuck the non-generic legacy versions behind explicit implementations.

ShoppingCart implements both IEnumerable<string> (modern, generic) and IEnumerable (legacy, non-generic). The generic version is implicit so it's visible on the class. The non-generic version is explicit, so it stays out of IntelliSense and only shows up when something asks for a plain IEnumerable. The class's public surface looks clean even though it satisfies two interfaces.

This pattern is so common that the BCL uses it on dozens of types: List<T>, Dictionary<TKey, TValue>, HashSet<T>, and most other generic collections all implement the non-generic counterparts explicitly so the legacy methods don't crowd the class's own API.

A cast or interface-typed variable is required to reach an explicit member. For value types, that cast also boxes the value onto the heap, which allocates. For reference types the cast is a no-op at runtime, so there's no allocation. This matters when designing structs that implement interfaces.

Reason 3: Different Behavior Through Different Interfaces

The third reason is less common but powerful. A class can provide one behavior for callers who use it as itself, and a different behavior for callers who reach it through the interface. The class's own method does one thing; the explicit implementation does something extra (or different).

Output (the timestamp will differ):

The class has a public Log for direct use, and the explicit ILoggable.Log for callers that go through the logging framework. Two callers, two behaviors, one object. Use this pattern sparingly because it can surprise readers (why does Log print different things depending on the variable's type?), but when the two callers really do want different things, it's the standard way to express that.

Mixed Implementation: Some Implicit, Some Explicit

A class doesn't have to pick one style for the whole interface. Each member is decided independently. Common methods that callers use often become implicit; methods that only matter through the interface stay explicit.

Pack and Dispatch are part of the order's normal API and end up implicit. Audit is something only the auditing framework uses, so it stays hidden behind the interface. The class header still says : IShipment, and the interface contract is fully satisfied; the only difference is which members are visible on the class itself.

The rule of thumb: implicit for members that are part of the class's natural API, explicit for members that are only meaningful through the interface (legacy compatibility, internal frameworks, conflicting names from a second interface).

Properties, Indexers, and Events

Explicit implementation works for every kind of interface member, not just methods. Properties, indexers, and events follow the same pattern: qualify the member with the interface name, drop the access modifier, and the member becomes interface-only.

Properties

The property is declared with string IDescribable.Description => ... instead of public string Description => .... The accessor (get) is part of the interface, so no public is allowed. Same hide-from-class behavior as with methods.

Indexers

Indexers use the qualified this[] form:

Events

Events use the same qualification, and the explicit form requires you to write out the add and remove accessors yourself (because there's no field-like event syntax for explicit implementations):

The event is reachable only through the IOrderPublisher reference. The class still has a public PlaceOrder method that raises it, which is fine; that method is on the class, not on the interface.

Re-implementing in a Subclass

Explicit interface members are not virtual by default, which makes overriding them in a subclass trickier than overriding regular methods. There are two patterns that work, and one that doesn't.

The pattern that doesn't work: trying to override the explicit member directly. Explicit members can't be marked virtual, so a subclass can't just write override against them.

Pattern 1: Re-implement the interface on the subclass. The subclass adds : IDiscountable to its own header (even though the base already implements it) and provides a fresh explicit implementation. The new implementation wins when the object is accessed through the interface.

The subclass re-states : IDiscountable and gets its own explicit slot. When the runtime resolves item.Apply() through the interface, it finds PremiumProduct's implementation, not BaseProduct's. This works because re-implementing the interface in the subclass creates a new interface mapping for that type.

Pattern 2: Have the explicit implementation call a `protected virtual` helper. When you want true subclass overriding without re-implementing the interface, put the actual logic in a protected virtual method and let the explicit implementation forward to it.

The interface method is still explicit on BaseProduct, so it stays out of the class's public surface. The real work happens in ApplyCore, which is protected virtual and behaves like any other polymorphic method. Subclasses override ApplyCore, and the interface call routes through the base's explicit implementation into the right override.

This second pattern is the standard recipe when you want both the API-hiding benefits of explicit implementation and the runtime polymorphism of a regular virtual chain. The Microsoft Framework Design Guidelines recommend it for exactly this case.

A Worked Example: Cart Implementing Two Interfaces

A complete example brings the rules together. A ShoppingCart implements both IDiscountable (the cart can be discounted as a whole) and IRefundable (the cart's contents can be refunded). Both interfaces declare Apply, but they mean different things. The cart also exposes a Total property and a clean iteration API, while still implementing IEnumerable<Product> for compatibility with LINQ.

cart.Apply() would not compile, because both Apply methods are explicit and the compiler refuses to guess which one is meant. Discount and refund are reached only through their interface-typed references. cart.Count() works because Count is a LINQ extension method on IEnumerable<T>, and the cart's generic enumerator is implicit, so LINQ sees it without a cast. The non-generic IEnumerable.GetEnumerator is explicit, so it doesn't show up in IntelliSense or clutter the class API, but it's still there for anything that asks for a plain IEnumerable.

The overall shape of the class shows how explicit implementation lets you satisfy multiple contracts cleanly. The cart "is" a discountable thing, "is" a refundable thing, and "is" a sequence of products, all at once, with each role reachable through the right reference type.

Pitfalls and Gotchas

A few things to watch out for when working with explicit implementations.

Forgetting that the class instance doesn't see the member. This is the most common complaint from people new to explicit implementation. You write cart.Apply() expecting it to work, and the compiler tells you CartItem does not contain a definition for Apply. The fix is a cast or an interface-typed variable. The error message is CS1061, and it points right at the call site.

Boxing when the implementing type is a struct. Casting a struct to an interface boxes the value. Every call to an explicit interface method on a struct allocates, because the cast itself does. For high-frequency calls on value types, prefer implicit implementation so the struct's own copy of the method runs without boxing.

Mixing implicit and explicit for the same member of the same interface. You can do this (as the property quick-check earlier showed), but readers find it confusing because the same name produces different behavior depending on the variable type. Use it deliberately, with a comment, and only when the two callers genuinely want different things.

Trying to mark explicit members `virtual`, `abstract`, or `override`. None of these modifiers is allowed on an explicit member. The compiler reports CS0106 for virtual/abstract/override, and the right pattern (as discussed above) is to forward from the non-virtual explicit member into a protected virtual helper.

Default interface methods interact with explicit implementation in subtle ways. A class can rely on a default interface method instead of providing its own implementation. If the class still wants to override the default, an explicit implementation is one valid way to do it. The two features compose, but the interactions are worth a careful read when you mix them.