Hi,
Have you ever noticed, while implementing an interface, .Net auto intellisense provides two options as below. The code generation for these two options differ and also the Explicit generates a problem and requires fix to avoid it. Below are the details.
Here is the code below for each of the options.
First Option: (Non Explicit)
public void InstantiateIn(Control container)
{
throw new NotImplementedException();
}
Second Option: (Explicit)
void ITemplate.InstantiateIn(Control container)
{
throw new NotImplementedException();
}
Problem with Explicit:
FxCop produces ‘Interface methods should be callable by child types’ error if we opt for the Explicit option. The explanation is as below.
· 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.
· Now, If the derived type re-implements (explicitly) the inherited interface method, the base implementation is no longer accessible. i.e The call through the current instance reference will invoke the derived implementation; this results in recursion and an eventual stack overflow.
Exception:
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 do either below.
A. Implement a new method that exposes the same functionality and is visible to derived types or
B. Change to a non-explicit implementation.
C. However, If a breaking change is acceptable, an alternative is to make the derived type sealed.
using System;
namespace DesignLibrary
{
public interface ITest
{
void SomeMethod();
}
public class ViolatingBase : ITest // Violating
{
void ITest.SomeMethod() // Explicit
{
// ...
}
}
public class FixedBase : ITest // Correct Approach (Point A)
{
void ITest.SomeMethod()
{
SomeMethod();
}
protected void SomeMethod()
{
// ...
}
}
public class FixedBase : ITest // Correct Approach (Point B)
{
public void SomeMethod()
{
SomeMethod();
}
}
sealed public class Derived : FixedBase, ITest // Correct Approach (Point C)
{
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();
}
}
}
Thanks & Regards,
Arun Manglick || Senior Tech Lead
No comments:
Post a Comment