Share via


Interface methods should be callable by child types

TypeName

InterfaceMethodsShouldBeCallableByChildTypes

CheckId

CA1033

Category

Microsoft.Design

Breaking Change

NonBreaking

Cause

An unsealed externally visible type provides an explicit method implementation of a public interface and does not provide an alternative externally visible method with the same name.

Rule Description

Consider a base type that explicitly implements a public interface method. A type that derives from the base type can only access the inherited interface method through a reference to the current instance (this in C#) that is cast to the interface. If the derived type re-implements (explicitly) the inherited interface method, the base implementation is no longer accessible. The call through the current instance reference will invoke the derived implementation; this results in recursion and an eventual stack overflow.

This rule does not report a violation for an explicit implementation of System.IDisposable.Dispose when an externally visible Close() or System.IDisposable.Dispose(Boolean) method is provided.

How to Fix Violations

To fix a violation of this rule, implement a new method that exposes the same functionality and is visible to derived types or change to a non-explicit implementation. If a breaking change is acceptable, an alternative is to make the type sealed.

When to Exclude Warnings

It is safe to exclude a warning from this rule if an externally visible method is provided that has the same functionality but a different name than the explicitly implemented method.

Example

The following example shows a type, ViolatingBase, that violates the rule and a type, FixedBase, that shows a fix for the violation.

using System;

namespace DesignLibrary
{
   public interface ITest
   {
      void SomeMethod();
   }

   public class ViolatingBase: ITest
   {
      void ITest.SomeMethod()
      {
         // ...
      }
   }

   public class FixedBase: ITest
   {
      void ITest.SomeMethod() 
      {
         SomeMethod();
      }

      protected void SomeMethod()
      {
         // ...
      }
   }

   sealed public class Derived: FixedBase, ITest
   {
      public void SomeMethod()
      {
         // The following would cause recursion and a stack overflow.
         // ((ITest)this).SomeMethod();

         // The following is unavailable if derived from ViolatingBase.
         base.SomeMethod();
      }
   }
}

See Also

Reference

Interfaces (C# Programming Guide)