C# – Why aren’t all method virtual or why doesn’t have each class at least one interface

cdesignnetphilosophyunit testing

This is more philosophical question, which address .NET platform, but maybe it is useful also for other languages. I'm doing lot of Unit Testing and especially when I'm using third-party components I often struggling with. In .NET is enormous claim to component design(er) to choice which method should be virtual or not. On one side is it component usage (what make sense to be virtual), on other is it component mockability. You can use Shims to mock up third party components but this leads often to bad design and complexity. As I can remember the discussion about make all methods be virtual (JAVA has it since beginning) in .NET was about performance. But it is still the issue? Why aren't all methods in .NET virtual or why doesn't have each class at least one interface?

Best Answer

As Anders says, its partly about performance and partly about locking down poorly-thought designs down to reduce the scope of trouble caused later by people blindly inheriting things that were not designed to be inherited.

Performance seems obvious - while most methods wont be noticed on modern hardware, a virtual getter might cause quite a noticeable hit, even on modern hardware that does rely more and more on easily predicted instructions in the CPU pipeline.

Now the reason to make everything virtual by default seems to be driven by one thing only: unit testing frameworks. It seems to me that this is a poor reason, where we are changing code to suit the framework rather than designing it properly.

Perhaps the issue is with the frameworks used here, they should improve to allow replacement of functions at runtime with injected shims rather than building code that does this (with all the hacks to get round private methods as well as non-virtual ones, not to mention static and 3rd party functions)

So the reason methods are not virtual by default is as Anders said, and any desire to make them virtual to suit some unit test tool is putting the cart before the horse, proper design beats artificial constraints.

Now you can mitigate all of this by using interfaces, or by reworking your entire codebase to use components (or microservices) that communicate via message passing instead of directly wired method calls. If you enlarge the surface of a unit for testing to be a component, and that component is entirely self-contained, you don't really need to screw with it to unit test it.

Related Topic