fxcop : Explicit method implementations in unsealed classes should provide alternate methods with protected accessibility

Published 20 July 5 5:3 PM | Ramon Smits
Well that is the formatted message of the following fxCop rule name ExplicitMethodImplementationsInUnsealedClassesHaveVisibleAlternates. Today I had this strange fxCop error that I really had to read about five times before I understood about 95% of the error. This error clearly needed some investigation instead of the usual refactoring with ReSharper (if you use VS2003 and fxCop then ReFactor is definitaly a time saver!). The error I am talking about is "Explicit method implementations in unsealed classes should provide alternate methods with protected accessibility". Which is a bigass name to begin with!

So lets read the extra information about this error:

Explicit method implementations are defined with private accessibility. Classes that derive from classes with explicit method implementations and choose to re-declare them on the class will not be able to call into the base class implementation unless the base class has provided an alternate method with appropriate accessibility.

When overriding a base class method that has been hidden by explicit interface implementation, in order to call into the base class implementation, a derived class must cast the base pointer to the relevant interface. When calling through this reference, however, the derived class implementation will actually be invoked, resulting in recursion and an eventual stack overflow.

The problem here was that I had a class implementing an interface method as follows.

A.
void ITest.SomeMethod()  { ...}

The interface could also be implemented as the following alternative.

B.
public void SomeMethod() { ...}

In situation A you can't call ITest.SomeMethod from within your implementing object directly. The only way is to cast this to an ITest reference to call ITest.SomeMethod(). I knew that but I didn't need it because I would write the code as in situation B. ofcourse. Funny thing is that I forgot to seal to class and fxCop reminded me to do this with this error. But this means that you should normally just use situation B. as the primary way of implementating an interface. Problems arise when implementing two interfaces that share methods with the same signature but would have different implementations.

Normally I don't seal classes that often but I was working an a class that did some communication with unmanaged resources and had some unsafe code in it as well. It is a device driver wrapper and I wanted it sealed so people would think not twice but a hundred times before changing logic and would make the driver unstable by inheriting from it. We use IOC a lot at the current project for external resources.  Having someone around that change the driver factory configuration to supply a new driver because they would think they can easily add some functinality to it would not really make me a happy person.
Filed under: ,

Comments

# Erwyn van der Meer said on July 20, 2005 3:06 PM:

Personally I always seal classes unless I explicitly design them to be base types.

Don Box advises in his book Essential .NET (p. 74): "In general, designing a type to be used as a base type is considerably more difficult than defining a type that will simple be used to instantiate objects. For that reason, it is good practice to mark all types as sealed unless you are willing to ensure that your type is safe to use as a base."

# Ramon Smits said on July 21, 2005 4:39 AM:

That explains why most framework classes can't be inherited from. So now I use reflector to decompile them and stuff them in my own namespace. I normally only seal facade classes, classes that only contain static methods and most classes that are marked as serializable and used for out-of-process communcation.

Ofcourse is it true that when you don't design a class as a base class then you obviously don't have thought about it. But does this say we then need to seal the class because we want to be extra precautious to be on the safe side?

I really love Don Box his presentation skills, his old time classic "Essential COM" and his devotion to soap but I can't really follow him in this design aspect.

# Erwyn van der Meer said on July 21, 2005 2:37 PM:

Ramon, if decompiling a sealed framework class and creating your own version of it works for you, then you don't really need inheritance. Containment of the framework class within your own class will probably suffice. The problem with creating unsealed classes without explicitly designing them to be base classes is the following. If you create an unsealed class you allow any derived class to be passed in for a method call instead of the base class. This is called type substitutability. The method that is called might make subtle assumptions on the behavior of the class. If you don't explicitly create a class to be derivable you probably don't document all those assumptions on what methods are expected to do. So it is easy for derived classes to violate that implicit behavioral contract. You may also run into subtle security issues. Eric Lippert has a good blog entry on this sealed/unsealed thing: http://blogs.msdn.com/ericlippert/archive/2004/01/22/61803.aspx.

# Ramon Smits said on July 22, 2005 1:32 PM:

@Erwyn : The only thing that's still on my mind is that sealing a class in a future version will be a breaking change and unsealing it won't. So maybe that should indeed be the way to go. First sealing it and if you would need to extend functionality by inheritance then do a good review if the super class that will be inherited from.

Well with inheritance you have the same problems as with containment. To subclass or the container will call methods in the right order to let the base class work as it should. It neither of the two magic will make sure that it won't blow. The base class will have to use a state machine to validate if things are going as they should.

I just want inheritance. That is something different then having inheritance and be able to override most methods of the base class.

# Erwyn van der Meer said on September 1, 2005 2:17 AM:

@Ramon. A late comment because I just had the sealed/unsealed discussion again and looked at this post and the comments again.

The problem is really less with containment. The problem is not so much that the base class will blow up if called incorrectly. That will indeed happen for both a subclass or the containing class. The issue is that consumers of the class that you want to inherit from can get into trouble if a subclass changes the behavior or the invariants of the baseclass.

I agree that this is not really an issue if the base class has no overridable/virtual methods and you just inherit. But in most frameworks you might use inheritance as an implementation detail. The baseclass could be a derived class itself and override virtual methods of its super classes. In that case you really might want to end the inheritance chain by sealing that type. This way "outsiders" cannot inherit from your type, change its behavior and pass it to a method on another type in the framework that really only expects the base class type (its behaviour, its invariants, etc.).