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();
}
}
}