Now, first of all, to successfully interop with an IUnknown COM interface the methods must be declared in exactly the same order as in the IDL. This makes sense, as there's no other way to know how to call which method. This excludes naive uses of inheritance right off the bat, because even if it worked, methods would be inserted at the end instead of their proper position. But that's not a problem here: we make sure the order is the same by including all methods. So does this work? No.

You can retrieve an ICorPublishAppDomainEnum, but if you call any methods on it, you'll get an exception that QueryInterface() failed for the ICorPublishEnum interface. What's happening here is that the marshaler is only interested in the interface that originally defined the methods. The declarations we have supplied only mean that every object that implements ICorPublishAppDomainEnum is also required to implement ICorPublishEnum—which it won't, as we just made that interface up.

In case you were wondering about the use of generics: those also don't work. Suppose we redeclare the interface like this:

This type cannot be JIT-compiled, and the first attempt to use it in any way will raise an EETypeLoadException. Almost nothing in interop marshaling is even aware of generics, and using them will cause all sorts of interesting low-level errors.

The moral of the story is not to get clever and use COM interfaces in the straightforward way they were intended to be used. More complicated scenarios where you need more flexibility can be handled in C++/CLI, where you can turn the reduced type safety into an advantage.