Labels

Monday, March 9, 2009

Implicit vs Explicit Interface Implementation Myth

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