I've been using the COM IServiceProvider interface for a while now, mostly through extensions to the ATL's IServiceProviderImpl and BEGIN_SERVICE_MAP. Last week, I've been writing some managed code where I wanted to use the same pattern based on the System.IServiceProvider interface. Unfortunately, it turned out that it's not exactly the same interface.

On the first glance, the two interfaces look sufficiently similar. Both interfaces have only one method - QueryService() (QS) in the unmanaged version and GetService() (GS) in the managed version (I do prefer the QS name), that takes a service identifier and returns an object that implements this service, the actual contract and behavior of the two method is quite different. QueryService() takes two in parameters - a service identifier (SID) and an interface identifier (IID), while GetService() takes only on parameter - Type.

Since a SID is just a GUID, QS() offers the ability to have an implementation-agnostic service identification in the client code. The actual service implementation can be changed completely while the SID used to discover the service can stay the same. Moreover, this allows the service provider implementation to be the one that maps SIDs and services.

The Type parameter in GS() on the other hand implies that the service discovery should be done based on the actual type of the implementation. This prevents services polimorphism, as any new implementation needs to be discovered through it's type, thus cannot replace previous implementation. It also requires more tight coupling between the IServiceProvider client and the services, as it forces the client to know the types that implement particular service. And at service implementation level, it makes it impossible to have aggregated services that consist of two or more objects that implement different facets, unless the service itself has a facet discovery mechanism. (Though, since a service is usually treated as a logical entity, it could be argued that the facet management is a function of the service itself, not the service provider)

Of course, it is possible to have an GS() implementation that treats the Type parameter as a random string identifier, thus mimicing the QS() behavior. However, while it does solve the two big limitations of the managed IServiceProvider, I find this approach undesireable - intentionally violating an interface contract is guaranteed to cause problems down the road.