Skip to content

Bits of .NET

Daily micro-tips for C#, SQL, performance, and scalable backend engineering.

  • Asp.Net Core
  • C#
  • SQL
  • JavaScript
  • CSS
  • About
  • ErcanOPAK.com
  • No Access
  • Privacy Policy
C#

C#: Why an Interface’s Default Method Only Runs When You Call It Through the Interface, Not Through the Class

- 03.10.26 - ErcanOPAK

🔧 The Default Interface Method That Only Worked Through One Door

A default interface method was added specifically so an interface could grow a new member without breaking every class that already implements it – any class that doesn’t override the member simply falls back to the body written on the interface itself. What catches people off guard is that this fallback is only reachable through a variable typed as the interface. The same object, accessed through a variable typed as the implementing class, doesn’t see that member at all – not as inherited, not as hidden, not as anything – because the compiler resolves it based entirely on the compile-time type doing the asking.

🔎 The Problem

public interface IGreeter
{
    string Greet() => "Hello from the default!";
}

public class EnglishGreeter : IGreeter
{
    // Deliberately doesn't override Greet() - relies on the default.
}

var greeter = new EnglishGreeter();
Console.WriteLine(greeter.Greet()); // Compile error: EnglishGreeter
                                     // has no member called Greet() -
                                     // the default implementation is
                                     // only visible through IGreeter.

IGreeter asInterface = greeter;
Console.WriteLine(asInterface.Greet()); // "Hello from the default!"
                                         // same object, different
                                         // compile-time view.

✅ Fix: Call It Through the Interface, or Implement It Explicitly

  • Call default interface members through an interface-typed reference (or variable), not through the concrete class type, since the compiler resolves them based on the compile-time type only.
  • Explicitly implement (override) the member in the class whenever it genuinely needs to be callable through the class’s own type, rather than relying on the default being reachable from anywhere.
  • Treat a default interface method as an opt-in fallback for interface consumers specifically, not as a free method that automatically becomes part of every implementing class’s own public surface.

⚠️ Why This Is Easy to Miss

  • The class compiles cleanly and the interface compiles cleanly; the only symptom is the missing member when accessed through the class type, which reads exactly like a member that was simply never written rather than one that exists but is inaccessible from that angle.
  • This is a different situation from an abstract base class with a virtual method, which is callable through the derived type – the comparison to familiar inheritance rules leads most C# developers to assume behavior default interface methods don’t actually have.

A default interface method isn’t part of the class that implements it – it’s part of the interface, visible only to whoever’s holding that interface, and nothing else.

— C# Best Practice

Related posts:

C#: Forcing Performance with MethodImpl (AggressiveInlining)

C#: Use global using to Import Namespaces Once

Clean Minimal APIs in .NET – Automatic DTO Binding Explained

Post Views: 3

Post navigation

Ajax: Fix a fetch() Call That Silently Succeeds With a 404 Page’s HTML Instead of Throwing an Error
JavaScript: Fix a Promise.race() Call Whose Losing Promises Keep Running in the Background After It Resolves

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

October 2026
M T W T F S S
 1234
567891011
12131415161718
19202122232425
262728293031  
« Sep    

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (950)
  • How to add default value for Entity Framework migrations for DateTime and Bool (938)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (836)
  • How to enable, disable and check if Service Broker is enabled on a database in SQL Server (624)
  • Add Constraint to SQL Table to ensure email contains @ (590)
  • Average of all values in a column that are not zero in SQL (553)
  • How to use Map Mode for Vertical Scroll Mode in Visual Studio (526)
  • Find numbers with more than two decimal places in SQL (468)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps
  • Photoshop: Fix a Color Profile Mismatch That Makes Printed Output Look Nothing Like What You Saw On Screen
  • WordPress: Fix Search Results That Return Pages From a Theme You Deactivated Months Ago
  • Visual Studio: Fix a Test Project That Builds Fine Alone but Fails to Discover Any Tests After a NuGet Restore
  • ASP.NET Core: Fix a File Upload That Times Out on Slow Connections Only Because Kestrel’s Minimum Data Rate Feature Kicked In
  • JavaScript: Fix an Array Destructuring Default Value That Silently Never Applies Because null Was Passed Instead of Undefined

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (950)
  • How to add default value for Entity Framework migrations for DateTime and Bool (938)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (836)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps

Social

  • ErcanOPAK.com
  • GoodReads
  • LetterBoxD
  • Linkedin
  • The Blog
  • Twitter
© 2026 Bits of .NET | Built with Xblog Plus free WordPress theme by wpthemespace.com