Updated for V1
Shawn Hargreaves wrote an excellent article, Taking out the Trash. Where he talks about the way XNA's ContentManager works. He writes this in response to a comment I made at the bottom of that article:
*At the moment the texture will only be shared within a single resource manager, so if two different managers both want to reference it, two copies will get loaded.
We did consider your idea of a third manager that could handle these shared requests, and I think it is a good one, but this didn't fit into the V1 schedule.
Although now I come to think about it, the Load method is virtual, so this functionality could be added fairly easily by subclassing the existing manager. I smell another blog post topic for sometime after we actually ship this stuff...*
Inspired by that response, I created a SmartContentManager class which does just that. It works by querying a ContentCoordinator whenever it goes to load content to see if that piece of content has already been loaded. If it has, it just asks the originating manager for the piece of content. Using it is as easy as:
ContentCoordinator coordinator = new ContentCoordinator();
Services.AddService(typeof(IContentCoordinator), coordinator);
ContentManager content = new SmartContentManager(Services, coordinator);
ContentManager content2 = new SmartContentManager(Services, coordinator);
In the example above, the content and content2 variables will be able to load assets which share other sub-assets without duplicating them in memory. To use the same example he does in his article, consider these two models: London, and Tokyo. Each one shares the BrickWall.tga texture.
ContentCoordinator coordinator = new ContentCoordinator();
ContentManager loaderA = new SmartContentManager(Services, coordinator);
ContentManager loaderB = new SmartContentManager(Services, coordinator);
Model a = loaderA.Load
Model b = loaderB.Load
When "loaderA" loads "London", it will also load the brickwall texture. But when "loaderB" loads "Tokyo", the coordinator will simply pick up the shared texture from "loaderA", and assign it to the "Tokyo" model.
The one caveat to all of this is actually one that Shawn mentions in his article. If you load "London", then "Tokyo", the unload "London", the brickwall texture will go along with it, thus causing errors when you try to render "Tokyo".
The only way to get around that using the SmartContentManager is if you happen to know that the BrickWall texture is shared amongst many different models. You can choose to simply instantiate it in a third SmartContentManager before loading the rest of the assets. That way you can wait to unload the shared content manager after you have unloaded the ones with the models in them.
I added the sample code to the Content Pipeline with Shared References sample, which can be downloaded here: